home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / lisp / eulisp / telos-cl.lha / telos-cl2.8.lsp < prev   
Text File  |  1993-08-09  |  88KB  |  2,362 lines

  1. #|
  2. Telos in Common Lisp.  Copyright (C) Russell Bradford, August 1992,
  3. rjb@maths.bath.ac.uk.
  4.  
  5. For educational use only.
  6.  
  7. An implementation of Telos as taken from the EuLisp document version 0.95,
  8. and from the "Balancing" paper by Harry Bretthauer et al.
  9.  
  10. There are some differences with the above descriptions, mostly due to
  11. the 2-valued nature of CL, some due to a passing attempt to integrate with the
  12. usual type hierarchy of CL, others due to laziness on my part.
  13.  
  14. Disclaimer: this code was written to help me to understand Telos and MOPs
  15. in general.  Thus there are probably many features, naiveities, or even bugs.
  16. Plus the optimisations are somewhat simplistic.  I am interested in
  17. hearing about bugs/improvements and so on, but won't necessarily act upon
  18. them.
  19.  
  20. Developed on AKCL, has run on CMU, Clisp, HCL and WCL in its lifetime.  Works
  21. best when compiled: otherwise somewhat slow!  See the documentation strings for
  22. defclass, defgeneric, defmethod for more information.
  23.  
  24. Added attractions:
  25. describe tells you much about an object.
  26. defstructure is a simple implementation of structures.
  27. class-hierarchy gives the current subclass hierarchy.
  28. instance-hierarchy gives the current class instance hierarchy.
  29.  
  30. Version 2.0:  First released version RJB 92/10/27
  31.         2.1:  Fixed bug in sorting applicable methods that was revealed by MI
  32.               module RJB 92/10/29
  33.         2.2:  Disambiguate find-key returning () to indicate key absent;
  34.               more checking in add-method and generic-prin RJB 93/01/11
  35.         2.3:  Add remove-subclass and change defclass to aid debugging
  36.               RJB 93/01/18
  37.         2.4:  Add method-lambda, call-method-function, apply-method-function;
  38.               change *method-list* to be a list of method-function-lambdas
  39.               RJB 93/01/20
  40.         2.5:  Major renaming of parts, now classes are <classes>
  41.               RJB 93/01/29
  42.         2.6:  Some tidying and rearrangement of redundant code: removed last
  43.               traces of support for unrestricted metaclasses
  44.               RJB 93/02/03
  45.         2.7:  Added generic-lambda, and subsequent tidying; added
  46.               selective discrimination
  47.               RJB 93/03/18
  48.         2.8:  Altered inheritance of initargs and initforms; added slot
  49.               initargs RJB 93/04/06
  50.  
  51. Thoughts for the day:
  52. Allow add-method to call compute-discriminating-function et al, and do
  53. extra optimisation.
  54. Share method-functions amongst compatible methods.
  55. Extend hierarchy to, e.g., standard-generic-function as a subclass of
  56. generic-function, etc., and have these as the standard system classes.  Then
  57. we can optimize system classes.
  58.   standard-class, standard-method, standard-generic-function,
  59.   standard-local-slot-description(?)
  60. Lazy finalization of classes and gfs.
  61. |#
  62.  
  63. #+CMU
  64. (defpackage :telos)
  65.  
  66. (in-package :telos)
  67.  
  68. #+PCL
  69. (unuse-package :pcl)
  70.  
  71. (shadow '(describe
  72.           #+CMU memq
  73.           #+KCL allocate))
  74.  
  75. (export '(generic-funcall primitive-ref primitive-class-of primitive-allocate
  76.           metaclass class abstract-class function-class object generic-function
  77.           method slot-description local-slot-description
  78.           class-of subclass? class? slot-description? function?
  79.           generic-function? method? defgeneric method-function-lambda
  80.           generic-lambda
  81.           method-lambda apply-method-function call-method-function
  82.           defmethod class-name class-instance-length class-direct-superclasses
  83.           class-direct-subclasses class-slot-descriptions class-initargs
  84.           class-precedence-list generic-function-name generic-function-domain
  85.           generic-function-method-class generic-function-method-initargs
  86.           generic-function-methods generic-function-method-lookup-function
  87.           generic-function-discriminating-function generic-function-cache
  88.           method-generic-function method-domain
  89.           method-function slot-description-name slot-description-initfunction
  90.           slot-description-slot-reader slot-description-slot-writer
  91.       slot-description-slot-initarg
  92.           slot-value-using-slot-description find-slot-description
  93.           slot-value make allocate initialize call-next-method
  94.           next-method? apply-method call-method compute-method-lookup-function
  95.           compute-discriminating-function add-method remove-method
  96.           find-method compatible-superclasses-p compatible-superclass-p
  97.           compute-class-precedence-list compute-inherited-initargs
  98.           compute-initargs compute-inherited-slot-descriptions
  99.           compute-slot-descriptions compute-specialized-slot-description
  100.           compute-specialized-slot-description-class
  101.           compute-defined-slot-description
  102.           compute-defined-slot-description-class
  103.           copy-object compute-and-ensure-slot-accessors compute-slot-reader
  104.           compute-slot-writer ensure-slot-reader
  105.           compute-primitive-reader-using-slot-description
  106.           compute-primitive-reader-using-class
  107.           ensure-slot-writer compute-primitive-writer-using-slot-description
  108.           compute-primitive-writer-using-class add-subclass defclass
  109.           generic-prin common cl-object class-hierarchy
  110.           instance-hierarchy structure-class structure defstructure
  111.           describe standard-function find-key required
  112.           <object>
  113.             <structure>
  114.             <class>
  115.               <structure-class>
  116.               <metaclass>
  117.               <abstract-class>
  118.               <function-class>
  119.               <common>
  120.             <method>
  121.             <slot-description>
  122.               <local-slot-description>
  123.             <cl-object>
  124.               <number>
  125.                 <rational>
  126.                   <integer>
  127.                   <ratio>
  128.                 <float>
  129.                 <complex>
  130.               <package>
  131.               <readtable>
  132.               <hash-table>
  133.               <random-state>
  134.               <stream>
  135.               <pathname>
  136.               <function>
  137.                 <generic-function>
  138.                 <standard-function>
  139.               <character>
  140.               <symbol>
  141.                 <null>
  142.               <array>
  143.                 <vector>
  144.                   <string>
  145.                   <bit-vector>
  146.               <sequence>
  147. ;                <vector>
  148. ;                  <string>
  149. ;                  <bit-vector>
  150.                 <list>
  151. ;                  <null>
  152.                   <cons>
  153.               <struct>))
  154.                   
  155. #+KCL
  156. (eval-when (compile)
  157.    (proclaim '(optimize (safety 2))))        ; checks structure refs
  158.  
  159. #+KCL
  160. (eval-when (load)
  161.   (format t "loading..."))
  162.  
  163. (defun generic-funcall (fun &rest args)
  164.   (cond ((functionp fun) (apply fun args))
  165.         ((generic-function? fun)
  166.          (apply (generic-function-discriminating-function fun) args))
  167.         (t (error "~a is not a function in GENERIC-FUNCALL" fun))))
  168.  
  169. (eval-when (compile load eval)
  170.  
  171. (defvar telos (find-package :telos)
  172.   "The Telos Package")
  173.  
  174. ) ; end of eval-when
  175.  
  176. (eval-when (compile)
  177.  
  178. (proclaim '(inline primitive-class-slots primitive-class-class
  179.                    primitive-ref setter-primitive-ref
  180.                    primitive-class-of setter-primitive-class-of))
  181.  
  182. ) ; end of eval-when
  183.  
  184. (defstruct (primitive-class (:print-function primitive-print))
  185.   class
  186.   slots)
  187.  
  188. (defun primitive-ref (s n)
  189.   (svref (primitive-class-slots s) n))
  190.  
  191. (defun setter-primitive-ref (s n v)
  192.   (setf (svref (primitive-class-slots s) n) v))
  193.  
  194. (defsetf primitive-ref setter-primitive-ref)
  195.  
  196. (defun primitive-class-of (cl)
  197.   (primitive-class-class cl))
  198.  
  199. (defun setter-primitive-class-of (cl val)
  200.   (setf (primitive-class-class cl) val))
  201.  
  202. (defsetf primitive-class-of setter-primitive-class-of)
  203.  
  204. (defconstant unbound (list 'unbound))
  205. (defun unbound () unbound)
  206. (defun unbound? (x) (eq x unbound))
  207.  
  208. (defun primitive-allocate (cl size)
  209.   "Args: class size
  210. Allocate and return an uninitialized object that has class CLASS,
  211. and which has size SIZE."
  212.   (make-primitive-class :class cl
  213.                         :slots (make-array size :initial-element unbound)))
  214.  
  215. ; object
  216. (defconstant object-slots ())
  217. (defconstant object-initargs ())
  218. (defconstant object-size 0)
  219.  
  220. ; class
  221. (defconstant %name 0)
  222. (defconstant %instance-length 1)
  223. (defconstant %direct-superclasses 2)
  224. (defconstant %direct-subclasses 3)
  225. (defconstant %slot-descriptions 4)
  226. (defconstant %initargs 5)
  227. (defconstant %precedence-list 6)
  228. (defconstant class-slots '(name instance-length direct-superclasses
  229.                            direct-subclasses slot-descriptions
  230.                            initargs class-precedence-list))
  231. (defconstant class-accessors '(class-name class-instance-length
  232.                                class-direct-superclasses
  233.                                class-direct-subclasses
  234.                                class-slot-descriptions class-initargs
  235.                                class-precedence-list))
  236. (defconstant class-inits '(:name :direct-superclasses :direct-slot-descriptions
  237.                            :direct-initargs))
  238. (defconstant class-size (length class-slots))
  239.  
  240.  
  241. ; generic-function
  242. ;(defconstant %name 0)
  243. (defconstant %domain 1)
  244. (defconstant %method-class 2)
  245. (defconstant %method-initargs 3)
  246. (defconstant %methods 4)
  247. (defconstant %method-lookup-function 5)
  248. (defconstant %discriminating-function 6)
  249. (defconstant %cache 7)
  250. (defconstant gf-slots '(name domain method-class method-initargs
  251.                         methods method-lookup-function discriminating-function
  252.                         cache))
  253. (defconstant gf-accessors '(generic-function-name generic-function-domain
  254.                             generic-function-method-class
  255.                             generic-function-method-initargs
  256.                             generic-function-methods
  257.                             generic-function-method-lookup-function
  258.                             generic-function-discriminating-function
  259.                             generic-function-cache))
  260. (defconstant gf-initargs '(:name :domain :function :method-class
  261.                            :method-initargs
  262.                            :methods :method-lookup-function
  263.                            :discriminating-function))
  264. (defconstant gf-size (length gf-slots))
  265.  
  266. ; method
  267. (defconstant %generic-function 0)
  268. ;(defconstant %domain 1)
  269. (defconstant %function 2)
  270. (defconstant method-slots '(generic-function domain function))
  271. (defconstant method-accessors '(method-generic-function method-domain
  272.                                 method-function))
  273. (defconstant method-initargs '(:domain :function :generic-function))
  274. (defconstant method-size (length method-slots))
  275.  
  276. ; slot-description
  277. (defconstant %reader 0)
  278. (defconstant %writer 1)
  279. (defconstant sd-slots '(reader writer))
  280. (defconstant sd-accessors '(slot-description-slot-reader
  281.                             slot-description-slot-writer))
  282. (defconstant sd-initargs '(:reader :writer))
  283. (defconstant sd-size (length sd-slots))
  284.  
  285. ; local-slot-description
  286. (defconstant %lsdname 2)
  287. (defconstant %initarg 3)
  288. (defconstant %initfunction 4)
  289. (defconstant lsd-slots (append sd-slots '(name initarg initfunction)))
  290. (defconstant lsd-accessors (append sd-accessors
  291.                               '(slot-description-name
  292.                 slot-description-initarg
  293.                                 slot-description-initfunction)))
  294. (defconstant lsd-initargs (append sd-initargs '(:name :initarg :initfunction)))
  295. (defconstant lsd-size (length lsd-slots))
  296.  
  297. ; accessors
  298. (eval-when (compile)
  299.   (proclaim '(inline class-name setter-class-name
  300.                      class-instance-length setter-class-instance-length
  301.                      class-direct-superclasses setter-class-direct-superclasses
  302.                      class-direct-subclasses setter-class-direct-subclasses
  303.                      class-slot-descriptions setter-class-slot-descriptions
  304.                      class-initargs setter-class-initargs
  305.                      class-precedence-list setter-class-precedence-list
  306.                      generic-function-name setter-generic-function-name
  307.                      generic-function-domain setter-generic-function-domain
  308.                      generic-function-method-class
  309.                      setter-generic-function-method-class
  310.                      generic-function-method-initargs
  311.                      setter-generic-function-method-initargs
  312.                      generic-function-methods setter-generic-function-methods
  313.                      generic-function-method-lookup-function
  314.                      setter-generic-function-method-lookup-function
  315.                      generic-function-discriminating-function
  316.                      setter-generic-function-discriminating-function
  317.                      generic-function-cache setter-generic-function-cache
  318.                      method-generic-function setter-method-generic-function
  319.                      method-domain setter-method-domain
  320.                      method-function setter-method-function
  321.                      slot-description-slot-reader
  322.                      setter-slot-description-slot-reader
  323.                      slot-description-slot-writer
  324.                      setter-slot-description-slot-writer
  325.              slot-description-initarg
  326.              setter-slot-description-initarg
  327.                      slot-description-name setter-slot-description-name
  328.                      slot-description-initfunction
  329.                      setter-slot-description-initfunction)))                 
  330.  
  331. (defun class-name (cl) (primitive-ref cl %name))
  332. (defun setter-class-name (cl val) (setf (primitive-ref cl %name) val))
  333. (defsetf class-name setter-class-name)
  334.  
  335. (defun class-instance-length (cl) (primitive-ref cl %instance-length))
  336. (defun setter-class-instance-length (cl val)
  337.   (setf (primitive-ref cl %instance-length) val))
  338. (defsetf class-instance-length setter-class-instance-length)
  339.  
  340. (defun class-direct-superclasses (cl) (primitive-ref cl %direct-superclasses))
  341. (defun setter-class-direct-superclasses (cl val)
  342.   (setf (primitive-ref cl %direct-superclasses) val))
  343. (defsetf class-direct-superclasses setter-class-direct-superclasses)
  344.  
  345. (defun class-direct-subclasses (cl) (primitive-ref cl %direct-subclasses))
  346. (defun setter-class-direct-subclasses (cl val)
  347.   (setf (primitive-ref cl %direct-subclasses) val))
  348. (defsetf class-direct-subclasses setter-class-direct-subclasses)
  349.  
  350. (defun class-slot-descriptions (cl) (primitive-ref cl %slot-descriptions))
  351. (defun setter-class-slot-descriptions (cl val)
  352.   (setf (primitive-ref cl %slot-descriptions) val))
  353. (defsetf class-slot-descriptions setter-class-slot-descriptions)
  354.  
  355. (defun class-initargs (cl) (primitive-ref cl %initargs))
  356. (defun setter-class-initargs (cl val)
  357.   (setf (primitive-ref cl %initargs) val))
  358. (defsetf class-initargs setter-class-initargs)
  359.  
  360. (defun class-precedence-list (cl) (primitive-ref cl %precedence-list))
  361. (defun setter-class-precedence-list (cl val)
  362.   (setf (primitive-ref cl %precedence-list) val))
  363. (defsetf class-precedence-list setter-class-precedence-list)
  364.  
  365. (defun generic-function-name (gf) (primitive-ref gf %name))
  366. (defun setter-generic-function-name (gf val)
  367.   (setf (primitive-ref gf %name) val))
  368. (defsetf generic-function-name setter-generic-function-name)
  369.  
  370. (defun generic-function-domain (gf) (primitive-ref gf %domain))
  371. (defun setter-generic-function-domain (gf val)
  372.   (setf (primitive-ref gf %domain) val))
  373. (defsetf generic-function-domain setter-generic-function-domain)
  374.  
  375. (defun generic-function-method-class (gf) (primitive-ref gf %method-class))
  376. (defun setter-generic-function-method-class (gf val)
  377.   (setf (primitive-ref gf %method-class) val))
  378. (defsetf generic-function-method-class setter-generic-function-method-class)
  379.  
  380. (defun generic-function-method-initargs (gf)
  381.   (primitive-ref gf %method-initargs))
  382. (defun setter-generic-function-method-initargs (gf val)
  383.   (setf (primitive-ref gf %method-initargs) val))
  384. (defsetf generic-function-method-initargs
  385.   setter-generic-function-method-initargs)
  386.  
  387. (defun generic-function-methods (gf) (primitive-ref gf %methods))
  388. (defun setter-generic-function-methods (gf val)
  389.   (setf (primitive-ref gf %methods) val))
  390. (defsetf generic-function-methods setter-generic-function-methods)
  391.  
  392. (defun generic-function-method-lookup-function (gf)
  393.   (primitive-ref gf %method-lookup-function))
  394. (defun setter-generic-function-method-lookup-function (gf val)
  395.   (setf (primitive-ref gf %method-lookup-function) val))
  396. (defsetf generic-function-method-lookup-function
  397.   setter-generic-function-method-lookup-function)
  398.  
  399. (defun generic-function-discriminating-function (gf)
  400.   (primitive-ref gf %discriminating-function))
  401. (defun setter-generic-function-discriminating-function (gf val)
  402.   (setf (primitive-ref gf %discriminating-function) val))
  403. (defsetf generic-function-discriminating-function
  404.   setter-generic-function-discriminating-function)
  405.  
  406. (defun generic-function-cache (gf) (primitive-ref gf %cache))
  407. (defun setter-generic-function-cache (gf val)
  408.   (setf (primitive-ref gf %cache) val))
  409. (defsetf generic-function-cache setter-generic-function-cache)
  410.  
  411. (defun method-generic-function (md) (primitive-ref md %generic-function))
  412. (defun setter-method-generic-function (md val)
  413.   (setf (primitive-ref md %generic-function) val))
  414. (defsetf method-generic-function setter-method-generic-function)
  415.  
  416. (defun method-domain (md) (primitive-ref md %domain))
  417. (defun setter-method-domain (md val)
  418.   (setf (primitive-ref md %domain) val))
  419. (defsetf method-domain setter-method-domain)
  420.  
  421. (defun method-function (md) (primitive-ref md %function))
  422. (defun setter-method-function (md val)
  423.   (setf (primitive-ref md %function) val))
  424. (defsetf method-function setter-method-function)
  425.  
  426. (defun slot-description-slot-reader (sd) (primitive-ref sd %reader))
  427. (defun setter-slot-description-slot-reader (sd val)
  428.   (setf (primitive-ref sd %reader) val))
  429. (defsetf slot-description-slot-reader setter-slot-description-slot-reader)
  430.  
  431. (defun slot-description-slot-writer (sd) (primitive-ref sd %writer))
  432. (defun setter-slot-description-slot-writer (sd val)
  433.   (setf (primitive-ref sd %writer) val))
  434. (defsetf slot-description-slot-writer setter-slot-description-slot-writer)
  435.  
  436. (defun slot-description-initarg (sd) (primitive-ref sd %initarg))
  437. (defun setter-slot-description-initarg (sd val)
  438.   (setf (primitive-ref sd %initarg) val))
  439. (defsetf slot-description-initarg setter-slot-description-initarg)
  440.  
  441. (defun slot-description-name (sd) (primitive-ref sd %lsdname))
  442. (defun setter-slot-description-name (sd val)
  443.   (setf (primitive-ref sd %lsdname) val))
  444. (defsetf slot-description-name setter-slot-description-name)
  445.  
  446. (defun slot-description-initfunction (sd) (primitive-ref sd %initfunction))
  447. (defun setter-slot-description-initfunction (sd val)
  448.   (setf (primitive-ref sd %initfunction) val))
  449. (defsetf slot-description-initfunction setter-slot-description-initfunction)
  450.  
  451. (defvar <metaclass> (primitive-allocate () class-size)
  452.   "The Telos metaclass METACLASS")
  453.  
  454. (defvar <class> (primitive-allocate <metaclass> class-size)
  455.   "The Telos metaclass CLASS")
  456.  
  457. (defvar <abstract-class> (primitive-allocate <metaclass> class-size)
  458.   "The Telos metaclass ABSTRACT-CLASS")
  459.  
  460. (defvar <function-class> (primitive-allocate <metaclass> class-size)
  461.   "The Telos metaclass FUNCTION-CLASS")
  462.  
  463. (defvar <object> (primitive-allocate <abstract-class> class-size)
  464.   "The Telos abstract class OBJECT")
  465.  
  466. (defvar <generic-function> (primitive-allocate <function-class> class-size)
  467.   "The Telos class GENERIC-FUNCTION")
  468.  
  469. (defvar <method> (primitive-allocate <class> class-size)
  470.   "The Telos class METHOD")
  471.  
  472. (defvar <slot-description> (primitive-allocate <abstract-class> class-size)
  473.   "The Telos abstract class SLOT-DESCRIPTION")
  474.  
  475. (defvar <local-slot-description> (primitive-allocate <class> class-size)
  476.   "The Telos class LOCAL-SLOT-DESCRIPTION")
  477.  
  478. ; don't print result
  479. (null (setf (primitive-class-of <metaclass>) <metaclass>))
  480.  
  481. ; CL classes
  482.  
  483. (defvar <common> (primitive-allocate <metaclass> class-size)
  484.   "The Telos metaclass COMMON")
  485.  
  486. (defvar <cl-object> (primitive-allocate <abstract-class> class-size)
  487.   "The Telos abstract class CL-OBJECT")
  488.  
  489. (defvar <struct> (primitive-allocate <abstract-class> class-size)
  490.   "The Telos abstract class STRUCT")
  491.  
  492. (defmacro memq (a b) `(member ,a ,b :test #'eq))
  493.  
  494. (defconstant cl-class-table (make-hash-table :test #'eq))
  495.  
  496. ; This will be overwritten later when we get around to defining CL classes.
  497. ; Hack due to (type-of ()) -> SYMBOL, not NULL as we might hope.
  498. (defvar <null> () "The Telos class NULL")
  499.  
  500. ; KCL uses conses for lambdas
  501. #+KCL
  502. (defvar <standard-function> () "The Telos class STANDARD FUNCTION")
  503.  
  504. (defun class-of (obj)
  505.   (cond ((primitive-class-p obj) (primitive-class-of obj))
  506.         ((null obj) <null>)
  507. #+KCL   ((and (consp obj) (functionp obj)) <standard-function>)
  508.         (t (let ((type (type-of obj)))
  509.              (cond ((gethash type cl-class-table))
  510.                    ((consp type)
  511.                     (gethash (car type) cl-class-table))
  512.                    ((symbolp type)
  513.                     (install-new-struct-class type))
  514.                    (t <object>))))))
  515.  
  516. (defun install-new-struct-class (type)
  517.   (let ((new (make <common>
  518.                    :name type
  519.                    :direct-superclasses (list <struct>))))
  520.     (setf (gethash type cl-class-table) new)
  521.     new))
  522.  
  523. #|
  524. (defun class-of (obj)
  525.   (cond ((primitive-class-p obj) (primitive-class-of obj))
  526.         ((null obj) <null>)
  527. #+KCL        ((and (consp obj) (functionp obj)) <standard-function>)
  528.         (t (let ((type (type-of obj)))
  529.              (or (gethash type cl-class-table)
  530.                  (when (consp type)
  531.                    (gethash (car type) cl-class-table))
  532.                  <object>)))))
  533. |#
  534.  
  535. (defvar primitive-metaclasses
  536.   (list <metaclass> <function-class> <abstract-class> <class> <common>))
  537.  
  538. (defun primitive-metaclass? (obj)
  539.   (memq obj primitive-metaclasses))
  540.  
  541. ; assume both are classes
  542. (defun subclass? (a b)
  543.   (cond ((eq a b) t)
  544.          ((null a) ())
  545.          (t (some #'(lambda (c) (subclass? c b))
  546.                  (class-direct-superclasses a)))))
  547.  
  548. (defun cpl-subclass? (a b)
  549.   (memq b (class-precedence-list a)))
  550.  
  551. (defun class? (a) (subclass? (class-of a) <class>))
  552.  
  553. (defun slot-description? (a) (subclass? (class-of a) <slot-description>))
  554.  
  555. (defun generic-function? (a) (subclass? (class-of a) <generic-function>))
  556.  
  557. (defun method? (a) (subclass? (class-of a) <method>))
  558.  
  559. #+telos-debug (progn
  560.  
  561. #+KCL (use-fast-links ())
  562.  
  563. ; temporary version while debugging
  564. ; take care to avoid any gf calls
  565. (defun primitive-print (obj str xx)
  566.   (declare (ignore xx))
  567.   (primitive-generic-prin obj str))
  568.  
  569. (defvar primitive-classes
  570.   (list <object> <class> <metaclass> <abstract-class> <function-class>
  571.         <generic-function> <method> <slot-description>
  572.         <local-slot-description>))
  573.  
  574. (defun primitive-generic-prin (obj str)
  575.   (let ((cl (primitive-class-of obj)))
  576.     (cond ((or (memq obj primitive-classes)
  577.                (primitive-metaclass? cl))
  578.            (format str "#class(~s [~s])"
  579.                    (class-name obj)
  580.                    (class-name cl)))
  581.           ((eq cl <local-slot-description>)
  582.            (format str "#slotd(~s)"
  583.                    (slot-description-name obj)))
  584.           ((eq cl <generic-function>)
  585.            (format str "#gfun~s"
  586.                    (cons (generic-function-name obj)
  587.                          (mapcar #'(lambda (o)
  588.                                      (cond ((class? o) (class-name o))
  589.                                            ((null o) '*)
  590.                                            (t unbound)))
  591.                                  (generic-function-domain obj)))))
  592.           ((eq cl <method>)
  593.            (format str "#method~s"
  594.                    (cons (if (generic-function?
  595.                               (method-generic-function obj))
  596.                              (generic-function-name
  597.                               (method-generic-function obj))
  598.                              :unattached)
  599.                           (mapcar #'(lambda (o)
  600.                                      (cond ((class? o) (class-name o))
  601.                                            ((null o) '*)
  602.                                            (t unbound)))
  603.                                   (method-domain obj)))))
  604.           (t (let ((sds (class-slot-descriptions (class-of obj))))
  605.            (format str "#object(")
  606.            (mapc #'(lambda (sd)
  607.              (if (slot-description? sd)
  608.                  (let ((name (slot-description-name sd)))
  609.                    (if (unbound? name)
  610.                    (format str "~s ~s " :??? :???)
  611.                    (format str "~s ~s "
  612.                        name
  613.                        (primitive-slot-value obj name))))
  614.                  (format str "~s ~s " :??? :???)))
  615.              sds)
  616.            (format str "[~s])"
  617.                (if (class? cl) (class-name cl) :???))))))
  618.   obj)
  619.  
  620. ) ; end of telos-debug
  621.  
  622. (defun init-class (cl name isize supers subs inits cpl)
  623.   (setf (class-name cl) name)
  624.   (setf (class-instance-length cl) isize)
  625.   (setf (class-direct-superclasses cl) supers)
  626.   (setf (class-direct-subclasses cl) subs)
  627.   (setf (class-slot-descriptions cl) ())
  628.   (setf (class-initargs cl) inits)
  629.   (setf (class-precedence-list cl) (cons cl cpl))
  630.   name)
  631.  
  632. (init-class <object> 'object object-size ()
  633.             (list <class> <method> <slot-description> <cl-object>)
  634.             () ())
  635. (init-class <class> 'class class-size (list <object>)
  636.             (list <metaclass> <abstract-class> <function-class> <common>)
  637.             class-inits (list <object>))
  638. (init-class <metaclass> 'metaclass class-size (list <class>) () class-inits
  639.             (list <class> <object>))
  640. (init-class <abstract-class> 'abstract-class class-size (list <class>) ()
  641.             class-inits (list <class> <object>))
  642. (init-class <function-class> 'function-class class-size (list <class>) ()
  643.             class-inits (list <class> <object>))
  644. ;(init-class <generic-function> 'generic-function gf-size (list <object>) ()
  645. ;            gf-initargs (list <object>))
  646. (init-class <method> 'method method-size (list <object>) ()
  647.             method-initargs (list <object>))
  648. (init-class <slot-description> 'slot-description sd-size (list <object>)
  649.             (list <local-slot-description>) sd-initargs (list <object>))
  650. (init-class <local-slot-description> 'local-slot-description lsd-size
  651.             (list <slot-description>) () lsd-initargs
  652.             (list <slot-description> <object>))
  653. (init-class <common> 'common class-size (list <class>) () class-inits
  654.             (list <class> <object>))
  655. (init-class <cl-object> 'cl-object object-size (list <object>)
  656.             (list <struct>) () (list <object>))
  657. (init-class <struct> 'struct object-size (list <cl-object>) ()
  658.             () (list <cl-object> <object>))
  659.  
  660. ; CL classes
  661.  
  662. (defmacro def-cl-class (name <name> supers cpl)
  663.   `(progn
  664.      (defvar ,<name> () ,(format () "The Telos class ~a" name))
  665.      (setq ,<name> (primitive-allocate <common> class-size))
  666.      (setf (class-name ,<name>) ',name)
  667.      (setf (class-instance-length ,<name>) 0)
  668.      (setf (class-direct-superclasses ,<name>) (list ,@supers))
  669.      (setf (class-direct-subclasses ,<name>) ())
  670.      (setf (class-slot-descriptions ,<name>) ())
  671.      (setf (class-initargs ,<name>) ())
  672.      (mapc #'(lambda (super)
  673.                (setf (class-direct-subclasses super)
  674.                      (cons ,<name> (class-direct-subclasses super))))
  675.            (list ,@supers))
  676.      (setf (class-precedence-list ,<name>)
  677.            (cons ,<name> (append (list ,@cpl) (list <cl-object> <object>))))
  678.      (setf (gethash ',name cl-class-table) ,<name>)
  679.      ',<name>))
  680.  
  681. (defmacro synonym (a b)
  682.   `(setf (gethash ',a cl-class-table) ,b))
  683.  
  684. (def-cl-class sequence <sequence> (<cl-object>) ())
  685. (def-cl-class list <list> (<sequence>) (<sequence>))
  686. (def-cl-class cons <cons> (<list>) (<list> <sequence>))
  687. (def-cl-class array <array> (<cl-object>) ())
  688. (synonym simple-array <array>)
  689. (def-cl-class vector <vector> (<sequence> <array>) (<sequence> <array>))
  690. (synonym simple-vector <vector>)
  691. (def-cl-class bit-vector <bit-vector> (<vector>) (<vector> <sequence> <array>))
  692. (synonym simple-bit-vector <bit-vector>)
  693. (def-cl-class string <string> (<vector>) (<vector> <sequence> <array>))
  694. (synonym simple-string <string>)
  695. #+KCL (synonym fat-string <string>)
  696. (def-cl-class symbol <symbol> (<cl-object>) ())
  697. (synonym keyword <symbol>)
  698. (def-cl-class null <null> (<list> <symbol>) (<list> <symbol> <sequence>))
  699. (def-cl-class character <character> (<cl-object>) ())
  700. (synonym string-char <character>)
  701. (synonym standard-char <character>)
  702. ;
  703. ; Now do generic-function which was delayed from above
  704. (def-cl-class function <function> (<cl-object>) ())
  705. (def-cl-class standard-function <standard-function> (<function>) (<function>))
  706. (synonym function <standard-function>)        ; overwrite
  707. (synonym compiled-function <standard-function>)
  708. ;
  709. (init-class <generic-function> 'generic-function gf-size (list <function>) ()
  710.            gf-initargs (list <function> <object>))
  711. (setf (class-direct-subclasses <function>)
  712.       (list <generic-function> <standard-function>))
  713. ;
  714. (def-cl-class pathname <pathname> (<cl-object>) ())
  715. (def-cl-class stream <stream> (<cl-object>) ())
  716. (def-cl-class random-state <random-state> (<cl-object>) ())
  717. (def-cl-class hash-table <hash-table> (<cl-object>) ())
  718. (def-cl-class readtable <readtable> (<cl-object>) ())
  719. (def-cl-class package <package> (<cl-object>) ())
  720. (def-cl-class number <number> (<cl-object>) ())
  721. (def-cl-class complex <complex> (<number>) (<number>))
  722. (def-cl-class float <float> (<number>) (<number>))
  723. (synonym short-float <float>)
  724. (synonym single-float <float>)
  725. (synonym double-float <float>)
  726. (synonym long-float <float>)
  727. (def-cl-class rational <rational> (<number>) (<number>))
  728. (def-cl-class ratio <ratio> (<rational>) (<rational> <number>))
  729. (def-cl-class integer <integer> (<rational>) (<rational> <number>))
  730. (synonym fixnum <integer>)
  731. (synonym bignum <integer>)
  732. (synonym bit <integer>)
  733.  
  734. (defun primitive-find-slot-position (cl name slots index)
  735.   (cond ((null slots)
  736.          (error "slot ~s not found in class ~s" name cl))
  737.          ((eq name (slot-description-name (car slots))) index)
  738.          (t (primitive-find-slot-position cl name (cdr slots) (+ index 1)))))
  739.  
  740. (defun primitive-slot-value (obj name)
  741.   (let ((cl (class-of obj)))
  742.     (primitive-ref obj (primitive-find-slot-position
  743.                         cl name
  744.                         (class-slot-descriptions cl) 0))))
  745. (defun setter-primitive-slot-value (obj name val)
  746.   (let ((cl (class-of obj)))
  747.     (setf (primitive-ref obj
  748.            (primitive-find-slot-position
  749.             cl name
  750.             (class-slot-descriptions cl) 0))
  751.           val)))
  752.  
  753. (defsetf primitive-slot-value setter-primitive-slot-value)
  754.  
  755. (eval-when (compile load eval)
  756.  
  757. (defun construct-name (fmt &rest args)
  758.   (let ((*print-case* :upcase))
  759.     (intern (apply #'format () fmt args))))
  760.  
  761. (defun reader2writer (name)
  762.   (construct-name "SETTER-~a" name))
  763.  
  764. (defun get-gf-name (name)
  765.   (cond ((symbolp name) name)
  766.          ((and (consp name) (eq (car name) 'setf))
  767.          (reader2writer (cadr name)))
  768.          (t (error "bad name for generic ~a" name))))
  769.  
  770. (defvar required (list 'required))
  771. (defvar absent (list 'absent))
  772. (defun absent? (x) (eq x absent))
  773.  
  774. (defun key2symbol (k)
  775.   (if (keywordp k)
  776.       (intern (symbol-name k))
  777.       k))
  778.  
  779. (defun symbol2key (s)
  780.   (if (keywordp s)
  781.       s
  782.       (intern (symbol-name s) :keyword)))
  783.  
  784. (defun find-key (name initargs default)
  785.   (let* ((key (symbol2key name))
  786.           (val (getf initargs key default)))
  787.     (if (eq val required)
  788.          (error "Missing required initarg ~s" name)
  789.          val)))
  790.  
  791. (defun filter-initargs (initargs ignore)
  792.   (cond ((null initargs) ())
  793.          ((memq (car initargs) ignore)
  794.           (filter-initargs (cddr initargs) ignore))
  795.          (t (cons (car initargs)
  796.                   (cons (cadr initargs)
  797.                        (filter-initargs (cddr initargs) ignore))))))
  798.  
  799. (defun do-defgeneric-methods (name initargs)
  800.   (cond ((null initargs) ())
  801.         ((eq (car initargs) :method)
  802.           (cons `(defmethod ,name ,@(cadr initargs))
  803.                (do-defgeneric-methods name (cddr initargs))))
  804.          (t (do-defgeneric-methods name (cddr initargs)))))
  805.  
  806. (defun required-args (domain)
  807.   (cond        ((atom domain) ())
  808.         ((eq (car domain) '&rest) ())
  809.         (t (cons (car domain)
  810.                  (required-args (cdr domain))))))
  811.  
  812. (defun gf-args (arglist)
  813.   (cond ((null arglist) ())
  814.         ((atom arglist) (list '&rest arglist))
  815.         ((eq (car arglist) '&rest) arglist)
  816.         ((atom (car arglist)) (cons (car arglist) (gf-args (cdr arglist))))
  817.         (t (cons (caar arglist) (gf-args (cdr arglist))))))
  818.  
  819. (defun proclaim-gf (name arglist)
  820.   (let ((args (mapcar #'(lambda (a) (if (eq a '&rest) '&rest t))
  821.                       (gf-args arglist))))
  822.     `(proclaim '(function ,name ,args t))))
  823.  
  824. ) ; end of eval-when
  825.  
  826. ; allows (defgeneric (setf foo) ...)
  827. (defmacro defgeneric (gfname arglist . initargs)
  828. "Syntax: (defgeneric gfname (arglist) {initarg}*), where
  829. gfname is {symbol | (setf symbol)},
  830. arglist is {{symbol | (symbol class)}+ [ { . | &rest} symbol ]}, and
  831. initarg is {key val}. Allowable initargs include
  832. :class                   the class of the generic function
  833. :method-class            the class of the associated methods
  834. :method-initargs         a list of {key val} initargs to be passed to
  835.                          calls of defmethod on this gfname
  836. :method                  a method to be attached to the generic function
  837. The :method initarg can be repeated."
  838.   (let* ((gf-class (find-key :class initargs '<generic-function>))
  839.          (method-class (find-key :method-class initargs '<method>))
  840.          (method-inits (find-key :method-initargs initargs ()))
  841.          (reqd (required-args arglist))
  842.          (domain (mapcar #'(lambda (a) (if (atom a) () (cadr a)))
  843.                          reqd))
  844.           (name (get-gf-name gfname)))
  845.     `(progn
  846.        (defvar ,name ()
  847.          ,(find-key :documentation initargs
  848.                     (format () "The generic function ~a ~a" name arglist)))
  849.        (setq ,name (make-generic-function
  850.                     ',name
  851.                     (list ,@domain)
  852.                     ,gf-class
  853.                     ,method-class
  854.                     (list ,@method-inits)
  855.                     (list 
  856.                      ,@(filter-initargs
  857.                         initargs
  858.                         '(:class :method-class :method :name
  859.                           :method-initargs :documentation)))))
  860.        ,(proclaim-gf name arglist)
  861.        (setf (symbol-function ',name)
  862.              (generic-function-discriminating-function ,name))
  863.        ,@(do-defgeneric-methods name initargs)
  864.        ,@(if (eq name gfname) () `((defsetf ,(cadr gfname) ,name)))
  865.        ',name)))
  866.  
  867. (defmacro generic-lambda (arglist . initargs)
  868. "Syntax: (generic-lambda (arglist) {initarg}*).
  869. See defgeneric for details."
  870.   (let* ((gf-class (find-key :class initargs '<generic-function>))
  871.          (method-class (find-key :method-class initargs '<method>))
  872.      (method-inits (find-key :method-initargs initargs ()))
  873.      (name (find-key :name initargs :anonymous))
  874.          (reqd (required-args arglist))
  875.          (domain (mapcar #'(lambda (a) (if (atom a) () (cadr a)))
  876.                          reqd))
  877.          (gl (gensym "GENERIC-LAMBDA")))
  878.     `(let ((,gl
  879.             (make-generic-function
  880.              ',name
  881.              (list ,@domain)
  882.              ,gf-class
  883.              ,method-class
  884.              (list ,@method-inits)
  885.              (list 
  886.               ,@(filter-initargs
  887.                  initargs
  888.                  '(:class :method-class :method :name
  889.                           :method-initargs :documentation))))))
  890.        ,@(do-defgeneric-methods gl initargs)
  891.        ,gl)))
  892.  
  893. (defun make-generic-function
  894.   (name domain gf-class method-class method-inits initargs)
  895.   (if (and (eq gf-class <generic-function>)
  896.            (eq method-class <method>)
  897.            (null method-inits)
  898.            (null initargs))
  899.       (primitive-make-generic-function name domain)
  900.       (apply #'make
  901.              gf-class
  902.              :name name
  903.              :domain domain
  904.              :method-class method-class
  905.              :method-initargs method-inits
  906.              initargs)))
  907.  
  908. (defun primitive-make-generic-function (name domain)
  909.   (when (every #'null domain)
  910.     (error "initialize of generic function with no discriminators: ~a"
  911.            name))
  912.   (let ((gf (primitive-allocate <generic-function> gf-size)))
  913.     (setf (generic-function-name gf) name)
  914.     (setf (generic-function-domain gf) domain)
  915.     (setf (generic-function-method-class gf) <method>)
  916.     (setf (generic-function-method-initargs gf) ())
  917.     (setf (generic-function-methods gf) ())
  918.     (setf (generic-function-cache gf) (new-cache))
  919.     (let* ((lookup #'(lambda (&rest values)
  920.                        (the-method-lookup-function gf values domain)))
  921.            (disc (compute-primitive-discriminating-function gf lookup)))
  922.       (setf (generic-function-method-lookup-function gf) lookup)
  923.       (setf (generic-function-discriminating-function gf) disc))
  924.     gf))
  925.  
  926. (defun check-nargs (gf nvals nargs)
  927.   (unless (>= nvals nargs)
  928.     (error "argument count mismatch: ~a requires ~r argument~:p,
  929. but ~r ~:*~[were~;was~:;were~] supplied"
  930.            gf nargs nvals)))
  931.  
  932. ; cache, c-n-m
  933. ; cf compute-discriminating-function
  934. ; takes same args as the gf
  935. (defun compute-primitive-discriminating-function (gf lookup-fn)
  936.   (let* ((cache (generic-function-cache gf))
  937.          (domain (generic-function-domain gf))
  938.          (nargs (length domain)))
  939.     #'(lambda (&rest values)
  940.         (check-nargs gf (length values) nargs)
  941.         (let ((applicable (cache-lookup
  942.                            values
  943.                            (discriminating-domain values domain)
  944.                            cache
  945.                            lookup-fn)))
  946.           (if (null applicable)
  947.               (error "no applicable methods ~s:~%arguments:~%~s~%classes:~%~s"
  948.                      gf
  949.                      values
  950.                      (mapcar #'class-of values))
  951.               (apply (car applicable)        ; apply-method-function
  952.                      (cdr applicable)
  953.                      values
  954.                      values))))))
  955.  
  956. (defun the-method-lookup-function (gf values domain)
  957.   (let* ((classes (discriminating-domain values domain))
  958.          (cpls (mapcar #'class-precedence-list classes)))
  959.     (sort (select-methods classes (generic-function-methods gf))
  960.           #'(lambda (md1 md2)
  961.               (sig<= (method-domain md1)
  962.                      (method-domain md2)
  963.                      cpls)))))
  964.  
  965. ; select-methods copies, as sort is destructive
  966. (defun select-methods (classes meths)
  967.   (if (null meths)
  968.       ()
  969.       (let ((md (car meths)))
  970.         (if (sig-applicable? classes (method-domain md))
  971.             (cons md (select-methods classes (cdr meths)))
  972.             (select-methods classes (cdr meths))))))
  973.  
  974. ; assume equal length
  975. (defun sig-applicable? (m1 m2)
  976.   (cond ((null m1) t)
  977.         ((or (null (car m2))                ; non-discriminating arg
  978.              (cpl-subclass? (car m1) (car m2)))
  979.          (sig-applicable? (cdr m1) (cdr m2)))
  980.         (t ())))
  981.  
  982. ; assume equal length
  983. (defun sig<= (sig1 sig2 cpls)
  984.   (cond ((null sig1) t)
  985.         ((eq (car sig1) (car sig2))        ; also case of non-discriminating arg
  986.          (sig<= (cdr sig1) (cdr sig2) (cdr cpls)))
  987.         (t (cpl-preceeds? (car sig1) (car sig2) (car cpls)))))
  988.  
  989. ; must have cl1 and cl2 in cpl
  990. (defun cpl-preceeds? (cl1 cl2 cpl)
  991.   (cond ((eq cl1 (car cpl)) t)
  992.         ((eq cl2 (car cpl)) ())
  993.         (t (cpl-preceeds? cl1 cl2 (cdr cpl)))))
  994.  
  995. ; cache
  996. (defun new-cache ()
  997.   (cons () ()))
  998.  
  999. (defmacro fast-cache (c) `(car ,c))
  1000. (defmacro slow-cache (c) `(cdr ,c))
  1001.  
  1002. (defun reset-cache (cache)
  1003.   (setf (fast-cache cache) ())
  1004.   (setf (slow-cache cache) ())
  1005.   cache)
  1006.  
  1007. (defun discriminating-domain (values domain)
  1008.   (cond ((null domain) ())
  1009.         ((car domain) (cons (class-of (car values))
  1010.                             (discriminating-domain (cdr values) (cdr domain))))
  1011.         (t (discriminating-domain (cdr values) (cdr domain)))))
  1012.  
  1013. ; cache
  1014. (defun cache-lookup (values classes cache lookup)
  1015.   (let ((fast (fast-cache cache))
  1016.         (slow (slow-cache cache)))
  1017.     (if (and (consp fast)
  1018.              (equal (car fast) classes))
  1019.          (cdr fast)
  1020.          (let ((cc (member classes slow :test #'equal :key #'car)))
  1021.           (if (null cc)
  1022.               (let ((applicable (apply lookup values)))
  1023.                 (if (null applicable)
  1024.                     ()
  1025.                     (let ((new (cons classes
  1026.                                      (mapcar #'method-function
  1027.                                              applicable))))
  1028.                       (setf (fast-cache cache) new)
  1029.                       (setf (slow-cache cache) (cons new slow))
  1030.                       (cdr new))))
  1031.               (progn
  1032.                  (setf (fast-cache cache) (car cc))
  1033.                  (cdar cc)))))))
  1034.  
  1035. ; c-n-m
  1036. (defmacro method-function-lambda (args . body)
  1037.   "Create a lambda that can be used as the function part of a method.
  1038. Syntax: (method-function-lambda (arglist) {form}*), where arglist is
  1039. {(symbol+ [ . symbol ]) | (symbol+ [ &rest symbol ])}"
  1040.   `#'(lambda (*method-list* *argument-list* ,@args) ,@(block-body () body)))
  1041.  
  1042. (defmacro named-method-function-lambda (name args . body)
  1043.   `#'(lambda (*method-list* *argument-list* ,@args) ,@(block-body name body)))
  1044.  
  1045. (defmacro method-lambda form
  1046.   "Create an anonymous method.
  1047. Syntax: (method-lambda {key val}* (arglist) {form}*), where arglist is
  1048. {{symbol | (symbol class)}+ [{ . | &rest} symbol]}"
  1049.   (let* ((initargs (defmethod-initargs form))
  1050.          (sig (defmethod-sig form))
  1051.          (body (defmethod-body form))
  1052.          (inits (filter-initargs initargs '(:class)))
  1053.          (method-class (find-key :class initargs absent))
  1054.          (args (defmethod-args sig))
  1055.          (domain (defmethod-domain sig)))
  1056.     `(make-method ,(if (absent? method-class)
  1057.                        '<method>
  1058.                        method-class)
  1059.                   (list ,@domain)
  1060.                   (method-function-lambda ,args ,@body)
  1061.                   (list ,@inits))))
  1062.  
  1063. (eval-when (compile load eval)
  1064.  
  1065. (defun block-body (gfname body)
  1066.   (if (consp body)
  1067.       (cond ((stringp (car body))
  1068.              (if (null (cdr body))
  1069.                  body
  1070.                  (block-body gfname (cdr body))))
  1071.             ((and (consp (car body))
  1072.                   (eq (caar body) 'declare))
  1073.              `(,(car body) ,@(block-body gfname (cdr body))))
  1074.             (t (if (null gfname)
  1075.                    `((progn *method-list* *argument-list*
  1076.                             ,@body))
  1077.                    `((block ,gfname *method-list* *argument-list* ,@body)))))
  1078.       ()))
  1079.  
  1080. ) ; eval-when
  1081.  
  1082. ; (defmethod foo ((a <integer>)...) ...)
  1083. ; (defmethod foo :method-initarg 23 ... ((a <integer>)...) ...)
  1084. ; allows (defmethod (setf foo) ...)
  1085. #-KCL
  1086. (defmacro defmethod (gfun . form)
  1087.   "Syntax: (defmethod gfname {key val}* (arglist) {form}*), where
  1088. gfname is {symbol | (setf symbol)}, and arglist is
  1089. {{symbol | (symbol class)}+ [ . symbol ]}"
  1090.   (let* ((initargs (defmethod-initargs form))
  1091.          (sig (defmethod-sig form))
  1092.          (body (defmethod-body form))
  1093.          (inits (filter-initargs initargs '(:class)))
  1094.          (method-class (find-key :class initargs absent))
  1095.          (args (defmethod-args sig))
  1096.          (domain (defmethod-domain sig))
  1097.          (gfn (get-gf-name gfun)))
  1098.     `(stable-add-method
  1099.       ,gfn
  1100.       (make-method ,(if (absent? method-class)
  1101.                         `(generic-function-method-class ,gfn)
  1102.                         method-class)
  1103.                    (list ,@domain)
  1104.                    (named-method-function-lambda ,gfn ,args ,@body)
  1105.                    (append
  1106.                     (list ,@inits)
  1107.                     (generic-function-method-initargs ,gfn))))))
  1108.  
  1109. ; problems with KCL not expanding macros and compiling lambdas at compiletime
  1110. #+KCL (defvar kcl-bug () "Bug in KCL")
  1111.  
  1112. #+KCL
  1113. (defmacro defmethod (gfun . form)
  1114.   "Syntax: (defmethod gfname {key val}* (arglist) {form}*), where
  1115. gfname is {symbol | (setf symbol)}, and arglist is
  1116. {{symbol | (symbol class)}+ [ . symbol ]}"
  1117.   (let* ((initargs (defmethod-initargs form))
  1118.          (sig (defmethod-sig form))
  1119.          (body (defmethod-body form))
  1120.          (inits (filter-initargs initargs '(:class)))
  1121.          (method-class (find-key :class initargs absent))
  1122.          (args (defmethod-args sig))
  1123.          (domain (defmethod-domain sig))
  1124.          (gfn (get-gf-name gfun)))
  1125.     `(progn
  1126.        (setq kcl-bug #'(lambda (*method-list* *argument-list* ,@args)
  1127.              ,@(block-body gfn body)))
  1128.        (stable-add-method
  1129.         ,gfn
  1130.         (make-method ,(if (absent? method-class)
  1131.                           `(generic-function-method-class ,gfn)
  1132.                           method-class)
  1133.                      (list ,@domain)
  1134.                      kcl-bug
  1135.                      (append
  1136.                       (list ,@inits)
  1137.                       (generic-function-method-initargs ,gfn)))))))
  1138.  
  1139. (eval-when (compile load eval)
  1140.  
  1141. (defun defmethod-initargs (form)
  1142.   (if (atom (car form))
  1143.       (cons (car form)
  1144.             (cons (cadr form) (defmethod-initargs (cddr form))))
  1145.       ()))
  1146.  
  1147. (defun defmethod-sig (form)
  1148.   (if (atom (car form))
  1149.       (defmethod-sig (cddr form))
  1150.       (car form)))
  1151.  
  1152. (defun defmethod-body (form)
  1153.   (if (atom (car form))
  1154.       (defmethod-body (cddr form))
  1155.       (cdr form)))
  1156.  
  1157. ; allows {symbol | (symbol+ [ . symbol ]) | (symbol* [ &rest symbol ]) }
  1158. (defun defmethod-args (sig)
  1159.   (cond ((null sig) ())
  1160.         ((atom sig) (list '&rest sig))
  1161.         ((eq (car sig) '&rest) sig)
  1162.         ((atom (car sig)) (cons (car sig) (defmethod-args (cdr sig))))
  1163.         (t (cons (caar sig) (defmethod-args (cdr sig))))))
  1164.  
  1165. (defun defmethod-domain (sig)
  1166.   (cond ((atom sig) ())
  1167.         ((eq (car sig) '&rest) ())
  1168.         ((atom (car sig))
  1169.          (cons () (defmethod-domain (cdr sig))))
  1170.         (t (cons (cadar sig) (defmethod-domain (cdr sig))))))
  1171.  
  1172. ) ; end of eval-when
  1173.  
  1174. (defun stable-add-method (gf md)
  1175.   (if (and (eq (class-of gf) <generic-function>)
  1176.            (eq (class-of md) <method>))
  1177.       (primitive-add-method gf md)
  1178.       (add-method gf md)))
  1179.  
  1180. ; cpl-subclass as we are talking about inheritance of behaviour
  1181. (defun check-method-domain (md gf)
  1182.   (let ((md-dom (method-domain md))
  1183.         (gf-dom (generic-function-domain gf)))
  1184.     (unless (= (length md-dom) (length gf-dom))
  1185.       (error "domain mismatch in add-method:~%~s~%~s" gf md))
  1186.     (unless (every #'(lambda (md gd)
  1187.                        (cond (gd (and md (cpl-subclass? md gd)))
  1188.                              (md ())
  1189.                              (t t)))
  1190.                    md-dom gf-dom)
  1191.       (error "attempt to extend domain in add-method:~%~s~%~s" gf md))))
  1192.  
  1193. ; cf add-method
  1194. ; cache
  1195. (defun primitive-add-method (gf md)
  1196.   (check-method-domain md gf)
  1197.   (when (generic-function? (method-generic-function md))
  1198.     (error "method already attached in add-method: ~s~%" md))
  1199.   (let ((old (primitive-find-method gf (method-domain md))))
  1200.     (when old (primitive-remove-method gf old)))
  1201.   (setf (generic-function-methods gf)
  1202.         (cons md (generic-function-methods gf)))
  1203.   (setf (method-generic-function md) gf)
  1204.   (reset-cache (generic-function-cache gf))
  1205.   gf)
  1206.  
  1207. (defun stable-find-method (gf domain)
  1208.   (if (and (eq (class-of gf) <generic-function>)
  1209.            (listp domain))
  1210.       (primitive-find-method gf domain)
  1211.       (find-method gf domain)))
  1212.  
  1213. ; cf find-method
  1214. (defun primitive-find-method (gf sig)
  1215.   (find sig (generic-function-methods gf)
  1216.         :test #'equal
  1217.         :key #'method-domain))
  1218.  
  1219. (defun stable-remove-method (gf md)
  1220.   (if (and (eq (class-of gf) <generic-function>)
  1221.            (eq (class-of md) <method>))
  1222.       (primitive-remove-method gf md)
  1223.       (remove-method gf md)))
  1224.  
  1225. ; cf remove method
  1226. ; cache
  1227. (defun primitive-remove-method (gf md)
  1228.   (let ((mds (generic-function-methods gf)))
  1229.     (when (memq md mds)
  1230.       (setf (generic-function-methods gf)
  1231.             (remove md mds :test #'eq))
  1232.       (setf (method-generic-function md) ())
  1233.       (reset-cache (generic-function-cache gf))))
  1234.   gf)
  1235.  
  1236. (defun make-method (method-class domain fn inits)
  1237.   (if (and (eq method-class <method>)
  1238.            (listp domain)
  1239.            (functionp fn)
  1240.            (null inits))
  1241.       (primitive-make-method domain fn)
  1242.       (apply #'make
  1243.              method-class
  1244.              :domain domain
  1245.              :function fn
  1246.              inits)))
  1247.  
  1248. (defun primitive-make-method (domain fn)
  1249.   (when (every #' null domain)
  1250.     (error "initialization of method with no discriminators"))
  1251.   (let ((md (primitive-allocate <method> method-size)))
  1252.     (setf (method-domain md) domain)
  1253.     (setf (method-function md) fn)
  1254.     md))
  1255.  
  1256. (defun primitive-make-slot-description (name index cl)
  1257.   (let ((sd (primitive-allocate <local-slot-description> lsd-size)))
  1258.     (setf (slot-description-name sd) name)
  1259.     (setf (slot-description-initarg sd) (symbol2key name))
  1260.     (let ((reader (generic-lambda ((obj cl))
  1261.             :method (((obj cl)) (primitive-ref obj index))))
  1262.       (writer (generic-lambda ((obj cl) val)
  1263.             :method (((obj cl) val)
  1264.                  (setf (primitive-ref obj index) val)))))
  1265.       (setf (generic-function-name reader)
  1266.         (construct-name "~a-~a" (class-name cl) name))
  1267.       (setf (generic-function-name writer)
  1268.         (construct-name "SETTER-~a-~a" (class-name cl) name))
  1269.       (setf (slot-description-slot-reader sd) reader)
  1270.       (setf (slot-description-slot-writer sd) writer))
  1271.     sd))
  1272.  
  1273. (defun make-slotds (names index cl)
  1274.   (if (null names)
  1275.       ()
  1276.       (cons (primitive-make-slot-description (car names) index cl)
  1277.             (make-slotds (cdr names) (+ index 1) cl))))
  1278.  
  1279. (let ((class-slotds (make-slotds class-slots 0 <class>)))
  1280.   (setf (class-slot-descriptions <class>) class-slotds)
  1281.   (setf (class-slot-descriptions <metaclass>) class-slotds)
  1282.   (setf (class-slot-descriptions <abstract-class>) class-slotds)
  1283.   (setf (class-slot-descriptions <function-class>) class-slotds)
  1284.   (setf (class-slot-descriptions <common>) class-slotds))
  1285.  
  1286. (setf (class-slot-descriptions <generic-function>)
  1287.       (make-slotds gf-slots 0 <generic-function>))
  1288.  
  1289. (setf (class-slot-descriptions <method>)
  1290.       (make-slotds method-slots 0 <method>))
  1291.  
  1292. (let ((sd-slotds (make-slotds lsd-slots 0 <slot-description>)))
  1293.   (setf (class-slot-descriptions <slot-description>)
  1294.         (list (car sd-slotds) (cadr sd-slotds)))
  1295.   (setf (class-slot-descriptions <local-slot-description>) sd-slotds))
  1296.  
  1297. ; more useful accessors
  1298. (defgeneric slot-value-using-slot-description ((sd <slot-description>) obj)
  1299.   :method (((sd <slot-description>) obj)
  1300.            (generic-funcall (slot-description-slot-reader sd) obj)))
  1301.  
  1302. (defgeneric (setf slot-value-using-slot-description)
  1303.   ((sd <slot-description>) obj val)
  1304.   :method (((sd <slot-description>) obj val)
  1305.            (generic-funcall (slot-description-slot-writer sd) obj val)))
  1306.  
  1307. (eval-when (compile)
  1308.   (defsetf slot-value-using-slot-description
  1309.     setter-slot-value-using-slot-description))
  1310.  
  1311. (defgeneric find-slot-description ((cl <class>) (symb <symbol>)))
  1312.  
  1313. (defmethod find-slot-description ((cl <class>) (symb <symbol>))
  1314.   (let ((sd (find (key2symbol symb)
  1315.                   (class-slot-descriptions cl)
  1316.                   :test #'eq
  1317.                   :key #'slot-description-name)))
  1318.     (if (null sd)
  1319.         (error "slot ~s not found in class ~s" symb cl)
  1320.         sd)))
  1321.  
  1322. (defun slot-value (obj name)
  1323.   (if (primitive-metaclass? (class-of (class-of obj)))
  1324.       (primitive-slot-value obj name)
  1325.       (slot-value-using-slot-description
  1326.        (find-slot-description (class-of obj) name)
  1327.        obj)))
  1328.  
  1329. (defun setter-slot-value (obj name val)
  1330.   (if (primitive-metaclass? (class-of (class-of obj)))
  1331.       (setf (primitive-slot-value obj name) val)
  1332.       (setf (slot-value-using-slot-description
  1333.              (find-slot-description (class-of obj) name)
  1334.              obj)
  1335.             val)))
  1336.  
  1337. (defsetf slot-value setter-slot-value)
  1338.  
  1339. (defun function? (a) (subclass? (class-of a) <function>))
  1340.  
  1341. ;;;--------------------------------------------------------------------
  1342. ;;;
  1343. ;;; the MOP proper starts here
  1344. ;;;
  1345. (defun make (cl &rest initargs)
  1346.   (initialize (allocate cl initargs) initargs))
  1347.  
  1348. (defgeneric allocate ((cl <class>) inits))
  1349.  
  1350. (defmethod allocate ((cl <abstract-class>) inits)
  1351.   (declare (ignore inits))
  1352.   (error "can't allocate an instance of an abstract-class ~s" cl))
  1353.  
  1354. (defmethod allocate ((cl <class>) inits)
  1355.   (declare (ignore inits))
  1356.   (primitive-allocate cl (class-instance-length cl)))
  1357.  
  1358. (defun check-legal-initargs (cl initargs)
  1359.   (let ((objinits (class-initargs cl)))
  1360.     (labels ((legal-initargs? (inits)
  1361.                (cond ((null inits) t)
  1362.                      ((memq (car inits) objinits)
  1363.                       (legal-initargs? (cddr inits)))
  1364.                      (t
  1365.                       (error "illegal initarg ~s in initialization of class ~a"
  1366.                              (car inits) cl)))))
  1367.       (legal-initargs? initargs))))
  1368.  
  1369. (defgeneric initialize ((obj <object>) initargs))
  1370.  
  1371. (defmethod initialize ((obj <object>) initargs)
  1372.   (let ((cl (class-of obj)))
  1373.     (check-legal-initargs cl initargs)
  1374.     (mapc #'(lambda (sd)
  1375.               (initialize-using-slot-description obj sd initargs))
  1376.           (class-slot-descriptions cl)))
  1377.   obj)
  1378.  
  1379. (defgeneric initialize-using-slot-description
  1380.   ((obj <object>) (sd <slot-description>) initargs))
  1381.  
  1382. (defmethod initialize-using-slot-description
  1383.   ((obj <object>) (sd <local-slot-description>) initargs)
  1384.   (let ((initarg (slot-description-initarg sd))
  1385.     (initfn (slot-description-initfunction sd)))
  1386.     (setf (slot-value-using-slot-description sd obj)
  1387.       (if (unbound? initarg)
  1388.           (if (function? initfn)
  1389.           (generic-funcall initfn)
  1390.           unbound)
  1391.           (let ((val (find-key initarg initargs absent)))
  1392.         (if (absent? val)
  1393.             (if (function? initfn)
  1394.             (generic-funcall initfn)
  1395.             unbound)
  1396.             val)))))
  1397.   obj)
  1398.  
  1399. ; relies on name capture
  1400. ; c-n-m
  1401. (defmacro call-next-method ()
  1402.   `(if (null *method-list*)
  1403.        (error "no next method")
  1404.        (apply (car *method-list*)        ; apply-method-function
  1405.               (cdr *method-list*)
  1406.               *argument-list*
  1407.               *argument-list*)))
  1408.  
  1409. ; c-n-m
  1410. (defmacro next-method? ()
  1411.   `(not (null *method-list*)))
  1412.  
  1413. ; c-n-m
  1414. (defun apply-method (md next-mds args)
  1415.   (apply (method-function md)
  1416.          (mapcar #'method-function next-mds)
  1417.          args
  1418.          args))
  1419.  
  1420. ; c-n-m
  1421. (defun call-method (md next-mds &rest args)
  1422.   (apply (method-function md) 
  1423.          (mapcar #'method-function next-mds)
  1424.          args
  1425.          args))
  1426.  
  1427. ;; c-n-m
  1428. (defun apply-method-function (mdfn next-mdfns args)
  1429.   (apply mdfn next-mdfns args args))
  1430.  
  1431. ; c-n-m
  1432. (defun call-method-function (mdfn next-mdfns &rest args)
  1433.   (apply mdfn next-mdfns args args))
  1434.  
  1435. (defmethod initialize ((gf <generic-function>) initargs)
  1436.   (let ((name (find-key :name initargs :anonymous))
  1437.         (domain (find-key :domain initargs required))
  1438.         (method-class (find-key :method-class initargs <method>))
  1439.         (method-inits (find-key :method-initargs initargs ()))
  1440.         (methods (find-key :methods initargs ())))
  1441.     (when (every #'null domain)
  1442.       (error "initialize of generic function with no discriminators: ~a"
  1443.              name))
  1444.     (call-next-method)
  1445.     (setf (generic-function-name gf) name)
  1446.     (setf (generic-function-method-class gf) method-class)
  1447.     (setf (generic-function-method-initargs gf) method-inits)
  1448.     (setf (generic-function-methods gf) ())
  1449.     (setf (generic-function-cache gf) (new-cache))
  1450.     (mapc #'(lambda (md) (add-method gf md)) methods)
  1451.     (finalize-generic gf))
  1452.   gf)
  1453.  
  1454. (defgeneric finalize-generic ((gf <generic-function>)))
  1455.  
  1456. (defmethod finalize-generic ((gf <generic-function>))
  1457.   (let* ((domain (generic-function-domain gf))
  1458.          (methods (generic-function-methods gf))
  1459.          (lookup (compute-method-lookup-function gf domain methods))
  1460.          (disc (compute-discriminating-function gf domain lookup methods)))
  1461.     (setf (generic-function-method-lookup-function gf) lookup)
  1462.     (setf (generic-function-discriminating-function gf) disc))
  1463.   (reset-cache (generic-function-cache gf))
  1464.   gf)
  1465.  
  1466. ; takes same args as the gf
  1467. (defgeneric compute-method-lookup-function
  1468.   ((gf <generic-function>) sig methods))
  1469.  
  1470. (defmethod compute-method-lookup-function
  1471.   ((gf <generic-function>) sig methods)
  1472.   (declare (ignore sig methods))
  1473.   (let ((domain (generic-function-domain gf)))
  1474.     #'(lambda (&rest values)
  1475.         (the-method-lookup-function gf values domain))))
  1476.  
  1477. (defgeneric compute-discriminating-function
  1478.   ((gf <generic-function>) domain lookup-fn meths))
  1479.  
  1480. ; cache
  1481. ; cf compute-primitive-discriminating-function
  1482. ; takes same args as the gf
  1483. (defmethod compute-discriminating-function
  1484.   ((gf <generic-function>) domain lookup-fn meths)
  1485.   (declare (ignore meths))
  1486.   (let ((cache (generic-function-cache gf))
  1487.         (domain (generic-function-domain gf))
  1488.         (nargs (length domain)))
  1489.     #'(lambda (&rest values)
  1490.         (check-nargs gf (length values) nargs)
  1491.         (let ((applicable (cache-lookup
  1492.                            values
  1493.                            (discriminating-domain values domain)
  1494.                            cache
  1495.                            lookup-fn)))
  1496.           (if (null applicable)
  1497.               (error
  1498.                "no applicable methods ~s:~%arguments:~%~s~%classes:~%~s"
  1499.                gf
  1500.                values
  1501.                (mapcar #'class-of values))
  1502.               (apply (car applicable)        ; apply-method
  1503.                      (cdr applicable)
  1504.                      values
  1505.                      values))))))
  1506.  
  1507. (defmethod initialize ((md <method>) initargs)
  1508.   (let ((domain (find-key :domain initargs required))
  1509.         (fn (find-key :function initargs required))
  1510.         (gf (find-key :generic-function initargs absent)))
  1511.     (declare (ignore fn))
  1512.     (when (every #'null domain)
  1513.       (error "initialization of method with no discriminators"))
  1514.     (call-next-method)
  1515.     (unless (absent? gf)
  1516.       (add-method gf md)) ; make sure the gf knows what's up
  1517.     md))
  1518.  
  1519. (defgeneric add-method ((gf <generic-function>) (md <method>)))
  1520.  
  1521. ; cf primitive-add-method
  1522. ; cache
  1523. (defmethod add-method ((gf <generic-function>) (md <method>))
  1524.   (check-method-domain md gf)
  1525.   (unless (subclass? (class-of md)
  1526.                      (generic-function-method-class gf))
  1527.     (error "method class mismatch in add-method:~%~s ~s" gf (class-of md)))
  1528.   (when (generic-function? (method-generic-function md))
  1529.     (error "method already attached in add-method: ~s~%" md))
  1530.   (let ((old (find-method gf (method-domain md))))
  1531.     (when old (remove-method gf old)))
  1532.   (setf (generic-function-methods gf)
  1533.         (cons md (generic-function-methods gf)))
  1534.   (setf (method-generic-function md) gf)
  1535.   (finalize-generic gf)                        ; resets cache
  1536.   gf)
  1537.  
  1538. (defgeneric find-method ((gf <generic-function>) sig))
  1539.  
  1540. ; cf primitive-find-method
  1541. (defmethod find-method ((gf <generic-function>) sig)
  1542.   (find sig (generic-function-methods gf)
  1543.         :test #'equal
  1544.         :key #'method-domain))
  1545.  
  1546. (defgeneric remove-method ((gf <generic-function>) (md <method>)))
  1547.  
  1548. ; cf primitive-remove-method
  1549. ; cache
  1550. (defmethod remove-method ((gf <generic-function>) (md <method>))
  1551.   (let ((mds (generic-function-methods gf)))
  1552.     (when (memq md mds)
  1553.       (setf (generic-function-methods gf)
  1554.             (remove md mds :test #'eq))
  1555.       (setf (method-generic-function md) ())
  1556.       (finalize-generic gf)))                ; resets cache
  1557.   gf)
  1558.  
  1559. (defmethod initialize ((sd <local-slot-description>) initargs)
  1560.   (declare (ignore sd))
  1561.   (find-key :name initargs required)
  1562.   (call-next-method))
  1563.  
  1564. (defmethod initialize ((cl <class>) initargs)
  1565.   (let ((name
  1566.          (find-key :name initargs :anonymous))
  1567.         (direct-supers
  1568.          (find-key :direct-superclasses initargs (list <object>)))
  1569.         (direct-slotds
  1570.          (find-key :direct-slot-descriptions initargs ()))
  1571.         (direct-inits
  1572.          (find-key :direct-initargs initargs ())))
  1573.     (call-next-method)
  1574.     (setf (class-name cl) name)
  1575.     (setf (class-direct-superclasses cl) direct-supers)
  1576.     (setf (class-direct-subclasses cl) ())
  1577.     (unless (compatible-superclasses-p cl direct-supers)
  1578.       (error "incompatible superclasses:~%~s can not be a subclass of ~%~s"
  1579.              cl direct-supers))
  1580.     (setf (class-precedence-list cl)
  1581.       (compute-class-precedence-list cl direct-supers))
  1582.     (setf (class-initargs cl)
  1583.       (compute-initargs cl direct-inits
  1584.                 (compute-inherited-initargs cl direct-supers)))
  1585.     (let* ((inherited-slotds (compute-inherited-slot-descriptions
  1586.                   cl direct-supers))
  1587.        (effective-slotds
  1588.         (compute-and-ensure-slot-accessors
  1589.          cl (compute-slot-descriptions cl direct-slotds inherited-slotds)
  1590.          inherited-slotds)))
  1591.       (setf (class-slot-descriptions cl) effective-slotds)
  1592.       (setf (class-instance-length cl) (length effective-slotds)))
  1593.     (mapcar #'(lambda (super)
  1594.         (add-subclass super cl)) direct-supers))
  1595.   cl)
  1596.  
  1597. (defgeneric compatible-superclasses-p ((cl <class>) superclasses))
  1598.   
  1599. ; si
  1600. (defmethod compatible-superclasses-p ((cl <class>) superclasses)
  1601.   (compatible-superclass-p cl (car superclasses)))
  1602.  
  1603. (defgeneric compatible-superclass-p ((cl <class>) (superclass <class>)))
  1604.  
  1605. (defmethod compatible-superclass-p ((cl <class>) (super <class>))
  1606.   (if (eq super <metaclass>)
  1607.       ()
  1608.       (subclass? (class-of cl) (class-of super))))
  1609.  
  1610. (defmethod compatible-superclass-p ((cl <class>) (super <abstract-class>))
  1611.   (declare (ignore cl super))
  1612.   t)
  1613.  
  1614. ; patchy here
  1615. (defmethod compatible-superclass-p ((cl <abstract-class>) (super <class>))
  1616.   (declare (ignore cl super))
  1617.   ())
  1618.  
  1619. ; patchy here
  1620. (defmethod compatible-superclass-p
  1621.   ((cl <abstract-class>) (super <abstract-class>))
  1622.   (declare (ignore cl super))
  1623.   t)
  1624.  
  1625. (defgeneric compute-class-precedence-list ((cl <class>) direct-supers))
  1626.  
  1627. ; si
  1628. (defmethod compute-class-precedence-list ((cl <class>) direct-supers)
  1629.   (cons cl (class-precedence-list (car direct-supers))))
  1630.  
  1631. (defgeneric compute-inherited-initargs ((cl <class>) direct-supers))
  1632.  
  1633. ; si
  1634. (defmethod compute-inherited-initargs ((cl <class>) direct-supers)
  1635.   (declare (ignore cl))
  1636.   (list (class-initargs (car direct-supers))))
  1637.  
  1638. (defgeneric compute-initargs ((cl <class>) direct-inits inherited-inits))
  1639.  
  1640. ; si
  1641. (defmethod compute-initargs ((cl <class>) direct-inits inherited-inits)
  1642.   (declare (ignore cl))
  1643.   (remove-duplicates (append direct-inits (car inherited-inits))
  1644.                      :test #'eq))
  1645.  
  1646. (defgeneric compute-inherited-slot-descriptions ((cl <class>) direct-supers))
  1647.  
  1648. ; si
  1649. (defmethod compute-inherited-slot-descriptions ((cl <class>) direct-supers)
  1650.   (declare (ignore cl))
  1651.   (list (class-slot-descriptions (car direct-supers))))
  1652.  
  1653. (defgeneric compute-slot-descriptions
  1654.   ((cl <class>) slotd-specs inherited-slotds))
  1655.  
  1656. ; si
  1657. (defmethod compute-slot-descriptions
  1658.   ((cl <class>) slotd-specs inherited-slotds)
  1659.   (let ((old-sd-names (mapcar #'slot-description-name (car inherited-slotds)))
  1660.         (new-sd-plist (mapcan #'(lambda (spec)
  1661.                                   (list (find-key :name spec required)
  1662.                                         spec))
  1663.                               slotd-specs)))
  1664.         (append
  1665.          (mapcar #'(lambda (sd)
  1666.                      (compute-specialized-slot-description
  1667.                       cl (list sd)
  1668.                       (getf new-sd-plist (slot-description-name sd))))
  1669.                  (car inherited-slotds))
  1670.          (mapcan #'(lambda (spec)
  1671.                      (if (memq (find-key :name spec required) old-sd-names)
  1672.                          ()
  1673.                          (list (compute-defined-slot-description
  1674.                                 cl spec))))
  1675.                  slotd-specs))))
  1676.  
  1677. (defgeneric compute-specialized-slot-description ((cl <class>) sds spec))
  1678.  
  1679. ; si
  1680. (defmethod compute-specialized-slot-description ((cl <class>) sds spec)
  1681.   (let* ((sd (car sds))
  1682.      (sdclass (compute-specialized-slot-description-class cl sds spec)))
  1683.     (if (null spec)
  1684.     (inherited-slot-description cl sd sdclass)
  1685.     (redefined-slot-description cl sd sdclass spec))))
  1686.  
  1687. ; inherited, but not redefined
  1688. (defun inherited-slot-description (cl sd sdclass)
  1689.   (declare (ignore cl))
  1690.   (if (eq sdclass (class-of sd))
  1691.       sd
  1692.       (make sdclass        ; what of other initargs?
  1693.         :name (slot-description-name sd)
  1694.         :reader (slot-description-slot-reader sd)
  1695.         :writer (slot-description-slot-writer sd)
  1696.         :initarg (slot-description-initarg sd)
  1697.         :initfunction (slot-description-initfunction sd))))
  1698.  
  1699. ; inherited and redefined
  1700. (defun redefined-slot-description (cl sd sdclass spec)
  1701.   (let* ((reader (find-key :reader spec
  1702.                (slot-description-slot-reader sd)))
  1703.      (writer (find-key :writer spec
  1704.                (slot-description-slot-writer sd)))
  1705.      (initfn (find-key :initfunction spec
  1706.                (slot-description-initfunction sd)))
  1707.      (name (find-key :name spec required))
  1708.      (initarg (find-key :initarg spec
  1709.                 (let ((ia (slot-description-initarg sd)))
  1710.                   (cond ((not (unbound? ia)) ia)
  1711.                     ((memq name (class-initargs cl)) name)
  1712.                     (t unbound))))))
  1713.     (apply #'make sdclass
  1714.        :reader reader
  1715.        :writer writer
  1716.        :initarg initarg
  1717.        :initfunction initfn
  1718.        (filter-initargs spec '(:reader :writer
  1719.                    :initarg :initfunction)))))
  1720.  
  1721. (defgeneric compute-specialized-slot-description-class ((cl <class>) sds spec))
  1722.  
  1723. (defmethod compute-specialized-slot-description-class ((cl <class>) sds spec)
  1724.   (declare (ignore cl sds spec))
  1725.   <local-slot-description>)
  1726.  
  1727. (defgeneric compute-defined-slot-description ((cl <class>) spec))
  1728.  
  1729. (defmethod compute-defined-slot-description ((cl <class>) spec)
  1730.   (let* ((name (symbol2key (find-key :name spec required)))
  1731.      (initarg (find-key :initarg spec
  1732.                 (if (memq name (class-initargs cl))
  1733.                 name
  1734.                 unbound))))
  1735.     (apply #'make
  1736.        (compute-defined-slot-description-class cl spec)
  1737.        :initarg initarg
  1738.        (filter-initargs spec '(:initarg)))))
  1739.  
  1740. (defgeneric compute-defined-slot-description-class ((cl <class>) spec))
  1741.  
  1742. (defmethod compute-defined-slot-description-class ((cl <class>) spec)
  1743.   (declare (ignore cl spec))
  1744.   <local-slot-description>)
  1745.  
  1746. (defgeneric copy-object ((obj <object>)))
  1747.  
  1748. (defmethod copy-object ((obj <object>))
  1749.   (let* ((cl (class-of obj))
  1750.          (new (allocate cl ())))
  1751.     (mapc #'(lambda (sd)
  1752.               (setf (slot-value-using-slot-description sd new)
  1753.                     (slot-value-using-slot-description sd obj)))
  1754.           (class-slot-descriptions cl))
  1755.     new))
  1756.  
  1757. (defgeneric compute-and-ensure-slot-accessors
  1758.   ((cl <class>) effective-slotds inherited-slotds))
  1759.  
  1760. ; si
  1761. ; if inheriting a sd, assume its reader & writer are OK
  1762. (defmethod compute-and-ensure-slot-accessors
  1763.   ((cl <class>) effective-slotds inherited-slotds)
  1764.   (mapc #'(lambda (sd)
  1765.             (unless (member (slot-description-slot-reader sd)
  1766.                             (car inherited-slotds)
  1767.                             :test #'eq :key #'slot-description-slot-reader)
  1768.               (let ((reader (compute-slot-reader cl sd effective-slotds))
  1769.                     (writer (compute-slot-writer cl sd effective-slotds)))
  1770.                 (setf (slot-description-slot-reader sd) reader)
  1771.                 (setf (slot-description-slot-writer sd) writer)))
  1772.             (ensure-slot-reader cl sd effective-slotds
  1773.                                 (slot-description-slot-reader sd))
  1774.             (ensure-slot-writer cl sd effective-slotds
  1775.                                 (slot-description-slot-writer sd)))
  1776.         effective-slotds)
  1777.   effective-slotds)
  1778.  
  1779. (defgeneric compute-slot-reader
  1780.   ((cl <class>) (slotd <slot-description>) effective-slotds))
  1781.  
  1782. (defmethod compute-slot-reader
  1783.   ((cl <class>) (slotd <slot-description>) effective-slotds)
  1784.   (declare (ignore slotd effective-slotds))
  1785.   (generic-lambda ((obj cl))))
  1786.  
  1787. (defmethod compute-slot-reader
  1788.   ((cl <class>) (slotd <local-slot-description>) effective-slotds)
  1789.   (declare (ignore effective-slotds))
  1790.   (let ((reader (generic-lambda ((obj cl)))))
  1791.     (setf (generic-function-name reader)
  1792.       (construct-name "~a-~a"
  1793.                           (class-name cl)
  1794.                           (slot-description-name slotd)))
  1795.     reader))
  1796.  
  1797. (defgeneric compute-slot-writer
  1798.   ((cl <class>) (slotd <slot-description>) effective-slotds))
  1799.  
  1800. (defmethod compute-slot-writer
  1801.   ((cl <class>) (slotd <slot-description>) effective-slotds)
  1802.   (declare (ignore slotd effective-slotds))
  1803.   (generic-lambda ((obj cl) val)))
  1804.  
  1805. (defmethod compute-slot-writer
  1806.   ((cl <class>) (slotd <local-slot-description>) effective-slotds)
  1807.   (declare (ignore effective-slotds))
  1808.   (let ((writer (generic-lambda ((obj cl) val))))
  1809.     (setf (generic-function-name writer)
  1810.       (construct-name "SETTER-~a-~a"
  1811.                           (class-name cl)
  1812.                           (slot-description-name slotd)))
  1813.     writer))
  1814.  
  1815. (defgeneric ensure-slot-reader
  1816.   ((cl <class>) (slotd <slot-description>)
  1817.    effective-slotds (reader <generic-function>)))
  1818.  
  1819. ; if there is a method, assume it's OK
  1820. (defmethod ensure-slot-reader
  1821.   ((cl <class>) (slotd <slot-description>)
  1822.    effective-slotds (reader <generic-function>))
  1823.   (when (null (generic-function-methods reader))
  1824.     (let ((primitive-reader
  1825.            (compute-primitive-reader-using-slot-description
  1826.             slotd cl effective-slotds)))
  1827.       (add-method reader
  1828.                   (method-lambda
  1829.                    :class (generic-function-method-class reader)
  1830.                    ((obj cl))
  1831.                    (funcall primitive-reader obj)))))
  1832.   reader)
  1833.  
  1834. (defgeneric compute-primitive-reader-using-slot-description
  1835.   ((slotd <slot-description>) (cl <class>) effective-slotds))
  1836.  
  1837. (defmethod compute-primitive-reader-using-slot-description
  1838.   ((slotd <slot-description>) (cl <class>) effective-slotds)
  1839.   (compute-primitive-reader-using-class cl slotd effective-slotds))
  1840.  
  1841. (defgeneric compute-primitive-reader-using-class
  1842.   ((cl <class>) (slotd <slot-description>) effective-slotds))
  1843.  
  1844. ; search on readers rather than names
  1845. (defmethod compute-primitive-reader-using-class
  1846.   ((cl <class>) (slotd <slot-description>) effective-slotds)
  1847.   (declare (ignore cl))
  1848.   (let ((reader (slot-description-slot-reader slotd)))
  1849.     (labels ((count (n slots)
  1850.                (if (eq reader (slot-description-slot-reader (car slots)))
  1851.                    n
  1852.                    (count (+ n 1) (cdr slots)))))
  1853.       (let ((index (count 0 effective-slotds)))
  1854.         #'(lambda (sd)
  1855.             (primitive-ref sd index))))))
  1856.  
  1857. (defgeneric ensure-slot-writer
  1858.   ((cl <class>) (slotd <slot-description>)
  1859.    effective-slotds (writer <generic-function>)))
  1860.  
  1861. ; if there is a method, assume it's OK
  1862. (defmethod ensure-slot-writer
  1863.   ((cl <class>) (slotd <slot-description>)
  1864.    effective-slotds (writer <generic-function>))
  1865.   (when (null (generic-function-methods writer))
  1866.     (let ((primitive-writer
  1867.            (compute-primitive-writer-using-slot-description
  1868.             slotd cl effective-slotds)))
  1869.       (add-method writer
  1870.                   (method-lambda
  1871.                    :class (generic-function-method-class writer)
  1872.                    ((obj cl) val)
  1873.                    (funcall primitive-writer obj val)))))
  1874.   writer)
  1875.  
  1876. (defgeneric compute-primitive-writer-using-slot-description
  1877.   ((slotd <slot-description>) (cl <class>) effective-slotds))
  1878.  
  1879. (defmethod compute-primitive-writer-using-slot-description
  1880.   ((slotd <slot-description>) (cl <class>) effective-slotds)
  1881.   (compute-primitive-writer-using-class cl slotd effective-slotds))
  1882.   
  1883. (defgeneric compute-primitive-writer-using-class
  1884.   ((cl <class>) (slotd <slot-description>) effective-slotds))
  1885.  
  1886. ; search on reader, rather than slot name
  1887. (defmethod compute-primitive-writer-using-class
  1888.   ((cl <class>) (slotd <slot-description>) effective-slotds)
  1889.   (declare (ignore cl))
  1890.   (let ((reader (slot-description-slot-reader slotd)))
  1891.     (labels ((count (n slots)
  1892.                (if (eq reader (slot-description-slot-reader (car slots)))
  1893.                    n
  1894.                    (count (+ n 1) (cdr slots)))))
  1895.       (let ((index (count 0 effective-slotds)))
  1896.         #'(lambda (sd val)
  1897.             (setf (primitive-ref sd index) val))))))
  1898.  
  1899. (defgeneric add-subclass ((super <class>) (sub <class>)))
  1900.  
  1901. ; would be nice to have weak pointers here
  1902. (defmethod add-subclass ((super <class>) (sub <class>))
  1903.   (setf (class-direct-subclasses super)
  1904.         (cons sub (class-direct-subclasses super))))
  1905.  
  1906. ; for debugging
  1907. (defgeneric remove-class ((cl <class>)))
  1908.  
  1909. ; si
  1910. ; dodgy if cl is a metaclass
  1911. (defmethod remove-class ((cl <class>))
  1912.   (let ((super (car (class-direct-superclasses cl))))
  1913.     (setf (class-direct-subclasses super)
  1914.           (remove cl (class-direct-subclasses super) :test #'eq)))
  1915.   cl)
  1916.  
  1917. (eval-when (compile load eval)
  1918.  
  1919. (defun strip-<> (sym)
  1920.   (let ((str (symbol-name sym)))
  1921.     (if (eql (aref str 0) #\<)
  1922.         (intern (string-trim "<>" str) (symbol-package sym))
  1923.         sym)))
  1924.  
  1925. (defun do-direct-slotds (slots)
  1926.   (cond ((null slots) ())
  1927.         ((atom (car slots))
  1928.          (cons `(list :name ',(car slots))
  1929.                (do-direct-slotds (cdr slots))))
  1930.     (t (let ((initf (find-key :initform (cdar slots) absent))
  1931.          (inita (find-key :initarg (cdar slots) absent)))
  1932.          (cons `(list :name ',(caar slots)
  1933.               ,@(if (absent? initf)
  1934.                                 ()
  1935.                                 `(:initfunction #'(lambda () ,initf)))
  1936.               ,@(if (absent? inita)
  1937.                 ()
  1938.                 `(:initarg ,(symbol2key inita)))
  1939.               ,@(filter-initargs (cdar slots)
  1940.                          '(:initform :accessor
  1941.                                                :initarg :reader :writer)))
  1942.            (do-direct-slotds (cdr slots)))))))
  1943.  
  1944. (defun find-slot-initargs (slots)
  1945.   (mapcan #'(lambda (s)
  1946.           (if (atom s)
  1947.           ()
  1948.           (let ((init (find-key :initarg (cdr s) absent)))
  1949.             (if (absent? init)
  1950.             ()
  1951.             (list (symbol2key init))))))
  1952.       slots))
  1953.  
  1954. (defun do-accessors (name slots)
  1955.   (mapcan #'(lambda (s)
  1956.               (if (atom s)
  1957.                   ()
  1958.                   (do-accessor name (car s) (cdr s))))
  1959.           slots))
  1960.  
  1961. (defun do-accessor (name slotname inits)
  1962.   (cond ((null inits) ())
  1963.         ((eq (car inits) :accessor)
  1964.          (let ((acc (cadr inits))
  1965.                (setter (reader2writer (cadr inits))))
  1966.            (append (do-reader acc name slotname)
  1967.                    (do-writer setter name slotname)
  1968.                    `((defsetf ,acc ,setter))
  1969.                    (do-accessor name slotname (cddr inits)))))
  1970.         ((eq (car inits) :reader)
  1971.          (let ((acc (cadr inits)))
  1972.            (append (do-reader acc name slotname)
  1973.                    (do-accessor name slotname (cddr inits)))))
  1974.         ((eq (car inits) :writer)
  1975.          (let ((setter (cadr inits)))
  1976.            (append (do-writer setter name slotname)
  1977.                    (do-accessor name slotname (cddr inits)))))
  1978.         (t (do-accessor name slotname (cddr inits)))))
  1979.  
  1980. (defun do-reader (acc name slotname)
  1981.   `((defvar ,acc () ,(format () "The ~s-~s slot reader" name slotname))
  1982.     (proclaim '(function ,acc (t) t))
  1983.     (let ((sdsr (slot-description-slot-reader
  1984.                  (find-slot-description ,name ',slotname))))
  1985.       (setq ,acc sdsr)
  1986.       (setf (symbol-function ',acc)
  1987.             (if (generic-function? sdsr)
  1988.                 (generic-function-discriminating-function sdsr)
  1989.                 sdsr)))))
  1990.  
  1991. (defun do-writer (setter name slotname)
  1992.   `((defvar ,setter () ,(format () "The ~s-~s slot writer" name slotname))
  1993.     (proclaim '(function ,setter (t t) t))
  1994.     (let ((sdsw (slot-description-slot-writer
  1995.                  (find-slot-description ,name ',slotname))))
  1996.       (setq ,setter sdsw)
  1997.       (setf (symbol-function ',setter)
  1998.             (if (generic-function? sdsw)
  1999.                 (generic-function-discriminating-function sdsw)
  2000.                 sdsw)))))
  2001.  
  2002. (defun do-predicates (name initargs)
  2003.   (cond ((null initargs) ())
  2004.         ((eq (car initargs) :predicate)
  2005.          (let ((pred (cadr initargs)))
  2006.            (append `((defgeneric ,pred ((obj <object>))
  2007.                        :method (((obj <object>)) ())
  2008.                        :method (((obj ,name)) t)))
  2009.                    (do-predicates name (cddr initargs)))))
  2010.         (t (do-predicates name (cddr initargs)))))
  2011.  
  2012. (defun do-constructors (name initargs)
  2013.   (cond ((null initargs) ())
  2014.         ((eq (car initargs) :constructor)
  2015.          (let ((con (cadr initargs)))
  2016.            (cons (if (atom con)
  2017.                      `(defun ,con (&rest inits)
  2018.                         (apply #'make ,name inits))
  2019.                      `(defun ,(car con) ,(cdr con)
  2020.                         (make ,name
  2021.                               ,@(mapcan #'(lambda (init)
  2022.                                             (list (symbol2key init)
  2023.                                                   init))
  2024.                                         (cdr con)))))
  2025.                  (do-constructors name (cddr initargs)))))
  2026.         (t (do-constructors name (cddr initargs)))))
  2027.  
  2028. (defun do-printfn (name initargs)
  2029.   (let ((pfn (find-key :print-function initargs absent)))
  2030.     (if (absent? pfn)
  2031.         ()
  2032.         `((defmethod generic-prin ((obj ,name) str)
  2033.             (funcall ,pfn obj str))))))
  2034.  
  2035. ) ; end of eval-when
  2036.  
  2037. (defmacro defclass (name supers slots . initargs)
  2038. "Syntax: (defclass name (supers) (slots) {initargs}*), where
  2039. name is a symbol,
  2040. supers is {class}*,
  2041. slots is {symbol | (symbol {slot-initargs}*)}, and
  2042. initargs and slot-initargs are {key val}. Allowable initargs include
  2043. :class               the class of the class begin defined
  2044. :initargs            a list of the allowable initargs for this class
  2045. :predicate           a predicate function for this class
  2046. :constructor         a constructor function for this class
  2047. :print-function      a function to be added as a method to generic-prin
  2048.                      to print an instance
  2049. The :predicate and :constructor initargs can be repeated.
  2050. Allowable slot-initargs include
  2051. :reader              a symbol to name a reader for this slot
  2052. :writer              a symbol to name a writer for this slot
  2053. :accessor            a symbol to name a reader for this slot; a writer
  2054.                      for this slot will be installed as the setf of the
  2055.                      reader
  2056. :initarg             a symbol to be the initarg for the slot
  2057. :initform            an initial value for the slot
  2058. The :reader, :writer, and :accessor initargs can be repeated."
  2059.   (let ((real-name (strip-<> name)))
  2060.     `(progn
  2061.        (defvar ,name ()
  2062.          ,(find-key :documentation initargs
  2063.                     (format () "The Telos class ~s" real-name)))
  2064.        (when (and (boundp ',name)                ; for debugging
  2065.                   (class? ,name))
  2066.          (remove-class ,name))
  2067.        (setq ,name
  2068.              (make ,(find-key :class initargs '<class>)
  2069.                    :name ',real-name
  2070.                    :direct-superclasses
  2071.                    (list ,@(if (null supers) '(<object>) supers))
  2072.                    :direct-slot-descriptions (list ,@(do-direct-slotds slots))
  2073.                    :direct-initargs
  2074.                    ',(append 
  2075.               (mapcar #'symbol2key (find-key :initargs initargs ()))
  2076.               (find-slot-initargs slots))
  2077.                    ,@(filter-initargs initargs '(:initargs :predicate
  2078.                                                  :class :constructor
  2079.                                                  :print-function
  2080.                                                  :documentation))))
  2081.        ,@(do-accessors name slots)
  2082.        ,@(do-predicates name initargs)
  2083.        ,@(do-constructors name initargs)
  2084.        ,@(do-printfn name initargs)
  2085.      ',name)))
  2086.  
  2087. #-telos-debug (progn
  2088.  
  2089. (defun primitive-print (obj str xx)
  2090.   (declare (ignore xx))
  2091.   (generic-prin obj str))
  2092.  
  2093. (defgeneric generic-prin ((obj <object>) str))
  2094.  
  2095. (defmethod generic-prin ((obj <object>) str)
  2096.   (let ((*print-case* :downcase)
  2097.         (sds (class-slot-descriptions (class-of obj))))
  2098.     (format str "#object(")
  2099.     (when sds
  2100.       (mapc #'(lambda (sd)
  2101.                 (let ((val (slot-value-using-slot-description sd obj)))
  2102.                   (format str "~a ~a " (slot-description-name sd)
  2103.                           (if (unbound? val)
  2104.                               :<unbound>
  2105.                               val))))
  2106.             sds))
  2107.     (format str "[~a])" (class-name (class-of obj)))))
  2108.  
  2109. (defmethod generic-prin ((obj <class>) str)
  2110.   (let ((*print-case* :downcase))
  2111.     (format str "#class(~a [~a])"
  2112.             (class-name obj)
  2113.             (class-name (class-of obj)))))
  2114.  
  2115. (defmethod generic-prin ((obj <slot-description>) str)
  2116.   (let ((*print-case* :downcase))
  2117.     (format str "#slotd([~a])"
  2118.             (class-name (class-of obj)))))
  2119.  
  2120. (defmethod generic-prin ((obj <local-slot-description>) str)
  2121.   (let ((*print-case* :downcase)
  2122.     (name (slot-description-name obj))
  2123.     (reader (slot-description-slot-reader obj))
  2124.     (class (class-name (class-of obj))))
  2125.     (if (generic-function? reader)
  2126.     (format str "#slotd(~a [~a])"
  2127.         (generic-function-name reader) class)
  2128.     (format str "#slotd(~a [~a])"
  2129.         name class))))
  2130.  
  2131. (defmethod generic-prin ((obj <generic-function>) str)
  2132.   (let ((*print-case* :downcase)
  2133.         (name (generic-function-name obj)))
  2134.     (format str "#gfun~a"
  2135.             (cons (if (unbound? name) :??? name)
  2136.                   (mapcar #'(lambda (cl)
  2137.                               (cond ((class? cl) (class-name cl))
  2138.                                     ((null cl) '*)
  2139.                                     (t :???)))
  2140.                           (generic-function-domain obj))))))
  2141.  
  2142. (defmethod generic-prin ((obj <method>) str)
  2143.   (let ((*print-case* :downcase))
  2144.     (format str "#method~a"
  2145.             (let ((gf (method-generic-function obj)))
  2146.               (cons (if (generic-function? gf)
  2147.                         (generic-function-name gf)
  2148.                         :unattached)
  2149.                     (mapcar #'(lambda (cl)
  2150.                               (cond ((class? cl) (class-name cl))
  2151.                                     ((null cl) '*)
  2152.                                     (t :???)))
  2153.                             (method-domain obj)))))))
  2154.  
  2155. (defmethod generic-prin ((obj <cl-object>) str)
  2156.   (princ obj str))
  2157.  
  2158. ) ; end of telos-debug
  2159.  
  2160. (defmethod allocate ((cl <common>) inits)
  2161.   (declare (ignore inits))
  2162.   (error "can't allocate a CL class: ~s" (class-name cl)))
  2163.  
  2164. ;----------------------------------------------------------------------
  2165.  
  2166. (defun class-hierarchy (&optional (slots? ()))
  2167.   (do-class-hierarchy (list <object>) 0 slots?)
  2168.   t)
  2169.  
  2170. (defun do-class-hierarchy (objlist depth slots?)
  2171.     (print-indent (car objlist) depth)
  2172.     (when slots?
  2173.       (when (class-slot-descriptions (car objlist))
  2174.         (prin-indent "slots: " depth)
  2175.         (princ (class-slots-names (car objlist)))
  2176.         (fresh-line))
  2177.       (when (class-initargs (car objlist))
  2178.         (prin-indent "initargs: " depth)
  2179.         (princ (class-initargs (car objlist)))
  2180.         (fresh-line)))
  2181.     (when (class-direct-subclasses (car objlist))
  2182.       (do-class-hierarchy (class-direct-subclasses (car objlist))
  2183.                           (+ depth 4) slots?))
  2184.     (when (cdr objlist)
  2185.       (do-class-hierarchy (cdr objlist) depth slots?)))
  2186.  
  2187. (defun class-slots-names (cl)
  2188.   (mapcar #'slot-description-name
  2189.           (class-slot-descriptions cl)))
  2190.  
  2191. (defun print-indent (obj depth)
  2192.     (prin-indent obj depth)
  2193.     (fresh-line))
  2194.  
  2195. (defun prin-indent (obj depth)
  2196.   (cond ((> depth 5) (princ "     ") (prin-indent obj (- depth 5)))
  2197.         ((= depth 0) (princ obj))
  2198.         ((= depth 1) (princ " ") (princ obj))
  2199.         ((= depth 2) (princ "  ") (princ obj))
  2200.         ((= depth 3) (princ "   ") (princ obj))
  2201.         ((= depth 4) (princ "    ") (princ obj))
  2202.         ((= depth 5) (princ "     ") (princ obj))))
  2203.  
  2204. (defun instance-hierarchy ()
  2205.   (let ((classes (collect-all-classes)))
  2206.     (do-instance-hierarchy <metaclass>
  2207.                            (remove <metaclass> classes)
  2208.                            0)
  2209.     (length classes)))
  2210.  
  2211. (defun collect-all-classes ()
  2212.   (remove-duplicates (collect-all-classes-aux <object>)
  2213.                      :test #'eq))
  2214.  
  2215. (defun collect-all-classes-aux (cl)
  2216.   (let ((subs (class-direct-subclasses cl)))
  2217.     (if (null subs)
  2218.         (list cl)
  2219.         (cons cl (mapcan #'(lambda (c)
  2220.                              (collect-all-classes-aux c))
  2221.                          subs)))))
  2222.  
  2223. (defun direct-instance? (cl sup)
  2224.   (eq (class-of cl) sup))
  2225.  
  2226. (defun class-direct-instances (cl classes)
  2227.   (remove-if #'(lambda (inst)
  2228.                  (not (direct-instance? inst cl)))
  2229.              classes))
  2230.  
  2231. (defun do-instance-hierarchy (cl classes depth)
  2232.   (let ((instances (class-direct-instances cl classes)))
  2233.     (print-indent cl depth)
  2234.     (mapc #'(lambda (inst)
  2235.               (do-instance-hierarchy inst classes (+ depth 4)))
  2236.           instances)))
  2237.  
  2238. ;------------------------------------------------------------------------------
  2239.  
  2240. #-telos-debug (progn
  2241.  
  2242. (defclass <structure-class> (<class>)
  2243.   ()
  2244.   :class <metaclass>)
  2245.  
  2246. (defmethod compute-and-ensure-slot-accessors
  2247.   ((c <structure-class>) effective-slotds inherited-slotds)
  2248.   (declare (ignore c inherited-slotds))
  2249.   (structure-c-a-e-s-a effective-slotds 0)
  2250.   effective-slotds)
  2251.  
  2252. (defun structure-c-a-e-s-a (effective-slotds index)
  2253.   (unless (null effective-slotds)
  2254.     (setf (slot-description-slot-reader (car effective-slotds))
  2255.           #'(lambda (obj)
  2256.               (primitive-ref obj index)))
  2257.     (setf (slot-description-slot-writer (car effective-slotds))
  2258.           #'(lambda (obj val)
  2259.               (setf (primitive-ref obj index) val)))
  2260.     (structure-c-a-e-s-a (cdr effective-slotds) (+ index 1))))
  2261.  
  2262. (defclass <structure> ()
  2263.   ()
  2264.   :class <structure-class>)
  2265.  
  2266. (defmethod initialize ((s <structure>) inits)
  2267.   (declare (ignore inits))
  2268.   (call-next-method)
  2269.   (mapc #'(lambda (sd)
  2270.             (when (unbound? (slot-value-using-slot-description sd s))
  2271.               (setf (slot-value-using-slot-description sd s) ())))
  2272.         (class-slot-descriptions (class-of s)))
  2273.   s)
  2274.  
  2275. (defmethod generic-prin ((s <structure>) str)
  2276.   (let* ((sclass (class-of s))
  2277.          (slots (class-slot-descriptions sclass))
  2278.          (names (mapcar #'slot-description-name slots))
  2279.          (vals  (mapcan #'(lambda (name sd)
  2280.                             (list name
  2281.                                   (slot-value-using-slot-description sd s)))
  2282.                         names slots)))
  2283.     (format str "#struct~s" (cons (class-name sclass) vals))))
  2284.  
  2285. (defmacro defstructure (name super slots . inits)
  2286.   (let ((initargs (mapcar #'(lambda (s) (if (atom s) s (car s)))
  2287.                           slots))
  2288.         (slotinits
  2289.          (mapcar #'(lambda (s)
  2290.                      (cond ((atom s)
  2291.                             `(,s :accessor ,(construct-name "~a-~a" name s)))
  2292.                            ((and (not (member :reader (cdr s)))
  2293.                                  (not (member :writer (cdr s)))
  2294.                                  (not (member :accessor (cdr s))))
  2295.                             `(,(car s) :accessor ,(construct-name
  2296.                                                    "~a-~a"
  2297.                                                    name
  2298.                                                    (car s))
  2299.                               ,@(cdr s)))
  2300.                            (t s)))
  2301.                  slots)))
  2302.     `(defclass ,name (,(if (null super) '<structure> super))
  2303.        ,slotinits
  2304.        ,@inits
  2305.        :initargs ,initargs
  2306.        ,@(unless (member :constructor inits)
  2307.            `(:constructor ,(construct-name "MAKE-~a" name)))
  2308.        ,@(unless (member :predicate inits)
  2309.            `(:predicate ,(construct-name "~a-P" name)))
  2310.        :class <structure-class>)))
  2311.  
  2312. ;------------------------------------------------------------------------------
  2313.  
  2314. (defvar *line-length* 60)
  2315.  
  2316. (defgeneric describe ((obj <object>)))
  2317.  
  2318. (defmethod describe ((obj <cl-object>))
  2319.   (call-next-method)
  2320. #-WCL
  2321.   (lisp:describe obj))
  2322.  
  2323. (defmethod describe ((obj <object>))
  2324.   (let ((str1 (format () "~%~s is an instance of " obj))
  2325.         (str2 (format () "~s~%" (class-of obj))))
  2326.     (princ str1)
  2327.     (when (> (+ (length str1) (length str2)) *line-length*) (terpri))
  2328.     (princ str2))
  2329.   (let ((sds (class-slot-descriptions (class-of obj))))
  2330.     (when sds
  2331.       (let ((*print-case* :downcase))
  2332.         (mapc #'(lambda (sd)
  2333.                   (let ((val (slot-value-using-slot-description sd obj)))
  2334.                     (format t "~a: ~a~%" (slot-description-name sd)
  2335.                             (if (unbound? val)
  2336.                                 '<unbound>
  2337.                                 val))))
  2338.               sds))))
  2339.   (values))
  2340.  
  2341. ) ; end of telos-debug
  2342.  
  2343. #+telos-debug (defun describe (x) (lisp:describe x))
  2344.  
  2345. ;------------------------------------------------------------------------------
  2346.  
  2347. #-CMU
  2348. (eval-when (load)
  2349.    (provide :telos))
  2350.  
  2351. (push :telos *features*)
  2352.  
  2353. (let ((*package* (find-package :user)))
  2354.   (shadowing-import '(describe
  2355.                       #+KCL allocate))
  2356. #+PCL (unuse-package :pcl)
  2357.   (use-package telos))
  2358.  
  2359. #+KCL
  2360. (eval-when (load)
  2361.   (format t "done.~%"))
  2362.